我有一个真正的exe应用程序,它基本上是trhu类。我创建了一个测试线束类mocktrhu,它继承了trhu并覆盖了trhu中的一些函数。
这两个项目是Visual Studio 2012 C++(非托管/本机)解决方案的一部分。
解决方案中的两个exe项目都可以顺利生成。
然后,我创建了一个VC++测试、本机单元测试项目,其中包括实际应用程序和模拟应用程序的测试。奇怪的是,实际应用程序的测试构建良好,但对于模拟应用程序,我得到了一个未解决的引用错误LNK2019。
1>------ Build started: Project: TRHUUnitTests, Configuration: Debug Win32 ------
1> TRHUUnitTests.cpp
1> Creating library MyAppUnderTest_SODebugTRHUUnitTests.lib and object MyAppUnderTest_SODebugTRHUUnitTests.exp
1>TRHUUnitTests.obj : error LNK2019: unresolved external symbol "public: __thiscall mocktrhu::mocktrhu(class config const &)" (??0mocktrhu@@QAE@ABVconfig@@@Z) referenced in function "public: void __thiscall TRHUUnitTests::UnitTests::TestMockedTRHUStart(void)" (?TestMockedTRHUStart@UnitTests@TRHUUnitTests@@QAEXXZ)
1>TRHUUnitTests.obj : error LNK2019: unresolved external symbol "public: virtual bool __thiscall mocktrhu::start(void)" (?start@mocktrhu@@UAE_NXZ) referenced in function "public: void __thiscall TRHUUnitTests::UnitTests::TestMockedTRHUStart(void)" (?TestMockedTRHUStart@UnitTests@TRHUUnitTests@@QAEXXZ)
1>MyAppUnderTest_SODebugTRHUUnitTests.dll : fatal error LNK1120: 2 unresolved externals
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========
问题单元测试是:
TEST_METHOD(TestMockedTRHUStart)
{
// test mocked TRHU startup
const int comport(3);
config conf(comport);
mocktrhu trhu1(conf);
trhu1.start();
}
这是代码:
单元测试代码,TRHUUnitTests.cpp:-
#include "CppUnitTest.h"
#include "application.hpp"
#include "MyAppTestHarness.hpp"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace TRHUUnitTests
{
TEST_CLASS(UnitTests)
{
public:
TEST_METHOD(TestMockedTRHUStart)
{
// test mocked TRHU startup
const int comport(3);
config conf(comport);
mocktrhu trhu1(conf);
trhu1.start();
}
TEST_METHOD(TestRealTRHUStart)
{
// test mocked TRHU startup - NOTE: requires connection to real hardware
const int comport(3);
config conf(comport);
trhu trhu1(conf);
trhu1.start();
}
};
}
真正的应用程序代码(单元测试适用于application.hpp):
#ifndef APPLICATION_HPP_
#define APPLICATION_HPP_
#include <iostream>
class config
{
public:
config(int comport) : comport_(comport) {}
int getport() const { return comport_; }
private:
int comport_;
};
class trhu
{
public:
trhu(const config& configuration) : config_(configuration) {}
virtual bool start()
{
// open com port - real hardware stuff
std::cout << "tchu program opening com port " << config_.getport() << 'n';
return true;
}
protected:
config config_;
};
#endif // APPLICATION_HPP_
实际应用程序代码实现(application.cpp):
#include "application.hpp"
int main() {
const int comport(3);
config conf(comport);
trhu trhu1(conf);
trhu1.start();
}
模拟应用程序(单元测试链接器错误-MyAppTestHarness.hpp):
#ifndef MYAPPTESTHARNESS_HPP_
#define MYAPPTESTHARNESS_HPP_
#include "application.hpp"
class mocktrhu : public trhu
{
public:
mocktrhu(const config& configuration);
virtual bool start();
};
#endif // MYAPPTESTHARNESS_HPP_
模拟应用程序代码实现(MyAppTestHarness.cpp):
#include "MyAppTestHarness.hpp"
#include <iostream>
mocktrhu::mocktrhu(const config& configuration)
: trhu(configuration) {}
bool mocktrhu::start()
{
// open com port - real hardware stuff
std::cout << "mocked tchu program opening com port: " << config_.getport() 'n';
return true;
}
int main() {
const int comport(3);
config conf(comport);
mocktrhu trhu1(conf);
trhu1.start();
}
完整性项目和解决方案文件:
顺便说一下,我只配置了调试项目,所以只看调试项目。
解决方案:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyAppUnderTest", "MyAppUnderTestMyAppUnderTest.vcxproj", "{F8EE9D1D-AA29-4B38-A579-7449C658EB7C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyAppTestHarness", "MyAppTestHarnessMyAppTestHarness.vcxproj", "{9052E9B6-FE19-4C76-B7E6-0BE44D0914AD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TRHUUnitTests", "TRHUUnitTestsTRHUUnitTests.vcxproj", "{D745B2BA-930F-43ED-A9DC-04FABE031F01}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F8EE9D1D-AA29-4B38-A579-7449C658EB7C}.Debug|Win32.ActiveCfg = Debug|Win32
{F8EE9D1D-AA29-4B38-A579-7449C658EB7C}.Debug|Win32.Build.0 = Debug|Win32
{9052E9B6-FE19-4C76-B7E6-0BE44D0914AD}.Debug|Win32.ActiveCfg = Debug|Win32
{9052E9B6-FE19-4C76-B7E6-0BE44D0914AD}.Debug|Win32.Build.0 = Debug|Win32
{D745B2BA-930F-43ED-A9DC-04FABE031F01}.Debug|Win32.ActiveCfg = Debug|Win32
{D745B2BA-930F-43ED-A9DC-04FABE031F01}.Debug|Win32.Build.0 = Debug|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
单元测试项目文件:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D745B2BA-930F-43ED-A9DC-04FABE031F01}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>TRHUUnitTests</RootNamespace>
<ProjectName>TRHUUnitTests</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTestinclude;../MyAppUnderTest;../MyAppTestHarness;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTestlib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTestinclude;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTestlib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="TRHUUnitTests.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
主应用程序项目文件:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F8EE9D1D-AA29-4B38-A579-7449C658EB7C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MyAppUnderTest</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="application.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="application.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
测试线束项目文件:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9052E9B6-FE19-4C76-B7E6-0BE44D0914AD}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MyAppTestHarness</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>../MyAppUnderTest</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="MyAppTestHarness.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MyAppTestHarness.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
我该怎么解决这个问题?
更新:
我注意到,我把有效的代码trhu类的实现放在了头文件中。如果我对测试线束模拟代码也这样做,那么它就可以链接了
#ifndef MYAPPTESTHARNESS_HPP_
#define MYAPPTESTHARNESS_HPP_
#include "application.hpp"
class mocktrhu : public trhu
{
public:
mocktrhu(const config& configuration)
: trhu(configuration) {}
virtual bool start()
{
// open com port - real hardware stuff
std::cout << "mocked tchu program opening com port: " << config_.getport() << 'n';
return true;
}
};
#endif // MYAPPTESTHARNESS_HPP_
但这当然不是我想要的。我想在实际代码中将头和实现分开。
是因为应用程序是exe而不是libs吗?任何想法都将不胜感激。
更新2:
可能为了让它发挥作用,我需要把mock放在单元测试项目中?
更新3:
我现在在想,要使用单元测试项目,我需要从实现真正的应用程序和mock作为ex,改为实现为库,这样我就可以在单元测试项目中使用libs。来自使用MS单元测试框架的人员的任何反馈。你是做什么的?
我在您的代码中找不到mocktrhu::mocktrhu(class config const &)
的实现(仅声明)。它在哪里实施?
MyAppTestHarness.cpp中没有方法体定义。此外,您可能需要导出您的类才能在其他项目中使用它。
为了能够从MS Test框架中调用函数,您需要能够将MS Test项目与函数的对象代码(或对象或其他)链接起来。在上面的例子中,"真正的"应用程序代码实现都在头文件中,所以不会造成问题。在模拟的应用程序代码中,实现代码不在头文件中,因此在这种情况下,MS测试项目不可用。因此出现了链接器错误。
问题是,在对象代码中无法链接的地方,无法测试代码。真实项目和模拟项目都是可执行类型的。您可以尝试链接从构建生成的中间对象文件,但这可能不是一个干净的解决方案。
我对设计做了一点改动,解决了这个问题。我将真实代码和模拟代码放入库中。因此,真正的应用程序仍然是一个exe项目,但它使用了一个实现程序逻辑的库。因此单元测试项目可以与这个库链接。模拟项目也是如此——它被改成了一个库。