модульное тестирование: статический метод создания - PullRequest
0 голосов
/ 08 сентября 2018

Я хочу начать писать модульные тесты для буферного класса, и я немного борюсь со статическим методом create.

class MyBuffer
{
public: 
  static MyBuffer* create(int32 bufSize)
  {
     if(!bufSize)
       return nullptr; 

     char* internalBuf = (char*)malloc(bufSize);
     if(nullptr == internalBuf) return nullptr; 

     return new MyBuffer(internalBuf, bufSize);
  }

 public bool write(void* data, int32 dataSize) {...}

private:
 MyBuffer(char* buf, int32 size) : internalBuf(buf), size(bufSize) {}

 char* internalBuf = nullptr; 
 int32 bufSize = 0;
};

//just dummy code
TEST(MyBuffer bufferWithZeroSize)
{ 
   auto buf = MyBuffer::create(0);
   ASSERT_True(nullptr == buf);
}

TEST(MyBuffer writeDataToBuffer)
{
  //arrange
  auto buf = MyBuffer::create(50); 
  ASSERT_NotNull(buf); //is this call needed

  //act
  buf->write(...); 

  //assert 
}

Проверка процесса создания MyBuffer прошла нормально.

В моем втором тесте можно предположить, что процесс создания MyBuffer прошел успешно? В противном случае я должен проверить это в «актовой» части модульного теста. Это звучит не очень разумно для меня, потому что я хочу проверять только одну вещь за единицу теста С другой стороны, я знаю, что вызов malloc может завершиться ошибкой.

Как вы тестируете объекты с помощью статического метода создания? Существуют ли какие-либо полезные стратегии тестирования или рекомендуется реорганизовать такие объекты? Я в основном использую статические методы create, чтобы вызывающая сторона объекта забыла правильно инициализировать объект. Поэтому для меня это звучит обоснованно.

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Я подозреваю, что вам не нужно писать буферный класс, и вместо этого можно использовать std::vector<char>. В общем, вы должны стараться держаться подальше от необработанного управления памятью (вообще не пишите new / delete / malloc / free (особенно delete / free)).

Что касается вопроса о модульном тестировании, то да, некоторые настройки подходят для того, чтобы приступить к настоящему тесту (или тестам). Когда вы повторно используете настройки в тестах, их часто называют Fixture. Я думаю, что нередко тестировать несколько вещей в одном тесте. Иногда производительность самих тестов тоже может быть проблемой, и тогда имеет смысл тестировать больше вещей, если установка дорогостоящая.

0 голосов
/ 08 сентября 2018

Я в основном использую статические методы создания, чтобы избежать того, что вызывающий объект забывает правильно инициализировать объект.

Нет способа, которым пользователь мог бы "забыть"для инициализации экземпляра MyBuffer, показанного ниже.

#include <cstddef>

class MyBuffer
{
private:
    std::size_t bufSize;
    char* internalBuf;

public:
    MyBuffer(std::size_t size)
    : bufSize{ size }
      internalBuf{ new char[size] },
    {}

    // + whats missing to satisfy the rule of 5

    bool write(char *data, std::size_t dataSize)
    {
        /* ... */
        return true;
    }
};

Примечание: не используйте malloc() без видимой причины.Используйте std::size_t для размера объектов в памяти.

Обновление относительно последнего комментария

#include <cstddef>
#include <stdexcept>
#include <algorithm>

class MyBuffer
{
public:
    static constexpr std::size_t min_size{ 10 };
    static constexpr std::size_t max_size{ 42 };

private:
    std::size_t bufSize;
    char* internalBuf;

public:
    MyBuffer(std::size_t size)
    : bufSize{ size == std::clamp(size, min_size, max_size) ?
               size : throw std::invalid_argument{ "size is out of range!" } },
      internalBuf{ new char[bufSize] }
    {}
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...