Qt

时间:2015-06-24 22:16:07

标签: c++ qt unit-testing

我正在尝试为我正在处理的项目编写单元测试(用Qt编写,用Qt编写),但由于我的代码在很大程度上取决于网络响应,因此我遇到了困难。我的项目包含一个具有三个重要功能的主类。工作流程看起来像这样:

// myclass.h
#include <QNetworkAccessManager>
class MyClass
{
    void function1();
    void function2();
    void function3();
    QNetworkAccessManager manager; // this is the object used to make network requests
}

// myclass.cpp
#include "myclass.h"
MyClass::function1()
{
    // this function should be called to start the chain of events

    // set up the first request
    manager.get("www.myserver.com");
}

MyClass::function2()
{
    // this function is called with the response of the request made in function1

    // process the results of the first request
    // set up the second request
    manager.get("www.yourserver.com");
}

MyClass::function3()
{
    // this function is called with the results of the second request

    // process the results of the second request
}

为了清晰起见,我遗漏了大部分细节,但上面的代码很好地说明了课程的组织方式。应该调用类中的一个函数来启动进程,并在网络请求完成时调用其他函数,以便可以处理这些请求的结果。

我想单独测试每个函数,以便我可以抛出许多不同的响应和不同的错误情况,以确保我的代码在每种情况下都能正确反应。问题是我不需要或希望我的功能在这些测试期间实际发出任何互联网请求。我在网上搜索过,但没有找到任何真正好的解决方案。以下是我找到的选项:

  1. 链接器技巧

    • 这里的想法是创建一个名为QNetworkAccessReply的模拟类,其虚拟get函数实际上不会发出任何网络请求。然后在编译期间,我将我的代码链接到这个模拟类,而不是Qt附带的那个。
    • 这个想法似乎是我发现的最干净的,不需要修改我的课程,但我还没有弄清楚如何在实践中实现这一点。
  2. 预处理程序指令

    • 这个想法涉及创建一个模拟对象,比方说QNetworkAccessManager_Mock,并在我的一个测试文件中定义一个宏,例如:#define TESTCASE。然后在我尝试测试的代码中,我将QNetworkAccessManager manager;的实例替换为:

      #ifdef TESTCASE
          QNetworkAccessManager_Mock manager;
      #else
          QNetworkAccessManager manager;
      #endif
      
    • 此选项在小型项目中相对容易实现,但在大型项目中可能会变得难以驾驭,因为您的代码必须充满#ifdef个部分。我不喜欢这个选项涉及的原始代码的修改级别

  3. 使用脚本编辑我的源文件

    • 我可以创建一个简单的脚本来运行我的源文件,而不是用模拟类替换QNetworkAccessManager的每个实例。
    • 这个选项允许我保持我的源代码不变,并且我不必在编译时正确地链接,但似乎需要很多额外的开销。
  4. 修改每个请求的目标网址

    • 我可以为我知道不存在的本地服务器选择一个网址,例如localhost:9000。在这种情况下,每个网络请求都会以可预测的方式失败,但是为了让它发挥作用似乎太过分了。
    • 或者,我的单元测试可以启动一个本地服务器,我可以从中返回一些预设的响应。在我看来,为了检查每个单独的函数如何响应,我看起来需要太多的开销,而且它仍然不能让我检查我的类如何响应必须处理网络故障的错误。
    • 在任何一种情况下,我仍然需要一种方法来修改网址,使用预处理程序指令,让我回到#2和#3的问题。
  5. 只是不要写测试。

    • 此选项违背了整个目的
  6. 如果我是编写依赖类的依赖项,那么存在大量用于模拟依赖项的示例。但是,似乎没有任何干净简单的解决方案来模拟其他库中存在的依赖类。上面概述的解决方案是我唯一的选择,还是我忽略了什么?你会推荐什么作为我的最佳选择?

1 个答案:

答案 0 :(得分:0)

我认为这是使用c ++类聚合的最佳解决方案。您可以创建Helper类,例如:

class Helper
{
    void function1();
    void function2();
    void function3();
}

在MyClass中聚集这个类。 MyClass.h:

#include <QNetworkAccessManager>
#include "Helper.h"
class MyClass
{
    void function1();
    void function2();
    void function3();
    Helper helper;
    QNetworkAccessManager manager; // this is the object used to make network requests
}

MyClass.cpp:

#include "myclass.h"
MyClass::function1()
{
    helper.function1();
    manager.get("www.myserver.com");
}

MyClass::function2()
{
    helper.function2();
    manager.get("www.yourserver.com");
}

MyClass::function3()
{
    helper.function3();
}

在这种情况下,您需要测试Helper类。