是否可以使用MSTest从c ++ dll测试“内部”类?

时间:2011-10-13 20:02:44

标签: c++ unit-testing mstest

我们目前正在尝试将单元测试添加到我们的c ++应用程序中。该应用程序由30个项目组成,可生成29个dll和1个exe。我们使用MSTest来运行我们的单元测试,因为它已经包含在Visual Studio 2010中。

它适用于声明为“公共”的类。这些课程在开头有这个:

#ifdef RESEAU_IMPL
    #define CLASS_DECL      _declspec(dllexport)
#else
    #define CLASS_DECL      _declspec(dllimport)
#endif 

但是对于所有其他类(90%的代码),它们都没有被公开,所以我们不能在测试中使用它们。

我在google上读过有关InternalVisibleTo属性的内容,但它似乎只适用于c#.NET程序集。我对吗?我也读过宣布我的班级“as_friend”,但我不知道该把它放在哪里。

简而言之:我想测试DLL中未导出/公开的类。我该怎么做?

由于

*编辑*

Gishu评论说,在非托管代码中无法进行单元测试,但这是可能的。请参阅,这是一个测试本机c ++代码的TestMethode。 CVersion在C ++ MFC中。

[TestMethod]
void AssignationCVersion()
{
    CVersion version1234(1,2,3,4);
    CVersion version4321(4,3,2,1);
    Assert::IsTrue(version1234 != version4321);
    version1234 = version4321;
    Assert::IsTrue(version1234 == version4321);
};

但似乎不可能的是使用特殊标签来测试内部函数。我是第一个同意测试内部方法不是好的做法,但这些DLL不是实用函数,而是“真实”应用程序的一部分(也许这是糟糕的设计,但它是在15年前完成的)。有人对这个问题有所了解吗?

3 个答案:

答案 0 :(得分:7)

另见问题: Unit testing non-exported classes in a DLL

这三个选项似乎是:

  • 将测试代码放在DLL中,以便它可以访问未导出的类和函数
  • 将包含测试代码的所有文件添加到测试项目中,以便将它们编译两次(不知道这是否适用于MSTEst,但是使用Boost测试或CPPunit这样做会是这样的)< / LI>
  • 将所有未导出的可测试代码构建到静态库中,然后将其链接到测试代码和DLL。

这些都有不同的问题。

将测试代码放入DLL中并不理想。您只将它包含在非生产版本中,在这种情况下,您不会测试您发布的内容,或者您​​将所有版本都包含在内,在这种情况下,您将提供测试代码,这可能是不合需要的。然后还需要某种入口点来访问这些测试,从而迫使编译器包含所有代码,防止优化器删除它,否则会被认为是不可访问的(可能是某些代码你正在测试无法从DLL中的任何公共方法访问,因此优化器可以决定将它们删除为死代码 - 让DLL中的测试阻止它。)

将源文件添加到两个项目会增加构建时间和维护复杂性。每次添加新的源文件或删除源文件时,都需要在两个位置添加。此外,根据代码的大小,这可能会大大增加构建时间,因为它必须两次构建大量代码。

将所有未导出的可测试代码放入静态库具有在解决方案中创建额外项目的缺点,并使组织更加复杂。您需要注意代码结构(例如,一个源文件应该只包含导出或非导出的代码),这意味着您需要为导出的部件和未导出的部件分别进行测试项目。但是,这意味着代码只编译一次,测试不是最终可执行文件的一部分,优化器可以完成全部工作。

根据DLL的公共接口的大小,即导出的类/函数的数量,第三个选项在我看来是最可行的。通常,您只有一个小型公共界面,它是更大内部结构的外观。除了公共外观之外的所有东西都可以进入一个单独的静态库,然后可以轻松地链接到测试可执行文件和DLL。

答案 1 :(得分:5)

无论是单元测试框架还是其他东西,都无法测试您看不到的代码。 Windows上的DLL仅导出已定义__declspec(dllexport)的符号。编译DLL时,任何其他符号都被视为内部 ,并且使用DLL时代码不可见。

这很重要,因为这意味着链接器可以优化,修改或删除未导出的代码。您要测试的代码可能根本不存在。它可能存在,但形式与您预期的不同。 DLL是根据一个契约编译的,任何用dllexport声明的东西都必须存在且可见,其他任何东西都必须工作。它不必从外部世界访问。

这不是MSTest的缺点(尽管它有很多其他缺点,并且是单元测试C ++代码的一个非常糟糕的选择)

如果要测试该代码,您有两种选择:

  • 使用dllexport
  • 导出
  • 将您的单元测试代码编写为dll本身的一部分。

答案 2 :(得分:-2)

好吧不要射杀信使。

  • Visual Studio单元测试(也就是使用MSTest.exe运行的测试)仅测试托管代码。您无法测试非托管C ++。 VS11(下一个版本)附带了一个新的原生单元测试框架。
  • InternalsVisibleTo就像你说的那样也只适用于托管代码。
  • 恕我直言你通常不需要测试内部课程。就像私有类型或方法一样,您可以通过使用它们的公共/公开方法对它们进行测试。因此,如果PublicA.Method1()是你的客户运用InternalHelper.Method2()的方式;然后我依靠PublicA.Method1()的测试来告诉我它们中的任何一个是否坏了。
  • 如果必须测试内部类,请尝试将它们公开(如果方法足够复杂,请参阅MethodObject重构)。或者您可以创建内部类的测试类a friend

class ProductionSUT
{
  // production code to be tested
  friend class TestProductSUT;
}

免责声明:没有试过这个......所以可能需要一些调整来安抚编译器。

相关问题