Я пытаюсь написать модульные тесты для приложения Qt5, которое я написал, но я озадачен тем, как обращаться с классами, которые включают в себя работу в сети. Мой основной класс включает в себя подкласс QTcpServer, который переопределяет QTcpServer ::comingConnection для создания объекта ClientConnection и передает его потоку:
void NetworkServer::incomingConnection(qintptr socketDescriptor)
{
QThread* clientThread = new QThread();
ClientConnection* clientConnection = new ClientConnection(socketDescriptor);
clientConnection->moveToThread(clientThread);
// connect signals & slots to ClientConnection (removed for clarity)
connect(clientThread, &QThread::started, clientConnection, &ClientConnection::run);
clientThread->start();
}
Класс ClientConnection использует socketDescriptor для открытия нового QTcpSocket в выделенном потоке, получения данных от клиента и их обработки.
ClientConnection::ClientConnection(int socketDescriptor, QObject *parent) :
QObject(parent), socketDescriptor(socketDescriptor)
{
tcpIncomingData = new QByteArray;
}
void ClientConnection::run()
{
QTcpSocket socket;
if(!socket.setSocketDescriptor(socketDescriptor)) {
emit sig_error(socket.error());
return;
}
if(socket.waitForReadyRead(5000)) {
*tcpIncomingData = socket.readAll();
qDebug() << "data received: " << tcpIncomingData;
} else {
qDebug() << "socket timed out!";
}
parseXmlData();
socket.disconnectFromHost();
socket.waitForDisconnected();
}
Этот класс не закончен, но я хочу начать писать тесты сейчас. Моя проблема заключается в том, как обрабатывать socketDescriptor. Я предполагаю, что мне нужно использовать какое-то внедрение зависимостей, но я не думаю, что это осуществимо без создания всего QTcpServer в тестовом примере.
Тестирование сетевого кода должно быть обычным делом в наши дни, поэтому должен быть общий способ справиться с этим, не включая половину моего приложения. Это кажется общим вопросом, но если требуется более подробная информация о моем конкретном приложении, пожалуйста, дайте мне знать.
Прежде всего, вы можете определить чистые интерфейсы (т.е. чисто абстрактные классы) для ваших занятий, так что насмешка и обмен ими не будет проблемой, скажем, IClientConnection
,
Затем вы можете объявить свои зависимости явно, то есть либо передать IClientConnection
фабрика или экземпляр IClientConnection
к NetworkServer
конструктор.
В вашем тесте теперь вы можете реализовать макет IClientConnection
и передать его или его фабрику (также может быть интерфейсом) конструктору в тесте. Возможно, вы захотите использовать умный указатель (shared_ptr или что-то родное для Qt), так что автоматическое освобождение ресурсов минимизирует ошибки.
Если ваше программное обеспечение растет, и вы пишете много ручного внедрения зависимостей, вы можете использовать библиотеку DI. Я недавно начал обзор некоторых из доступных библиотек C ++ DI.
Наконец, вы можете далеко уйти, посмеявшись над своими зависимостями, используя фальшивую среду, такую как googlemock.
Других решений пока нет …