如何在多个测试项目中 运行 只使用一次单例方法
How to run singleton method only once in multiple test projects
我有三个测试项目。所有这些都引用自模型项目:
我在模型项目中创建了 TestBase class 并将其用作所有测试 class 的基础 class。
继承看起来像这样:
[TestClass]
public class UnitTest1 : TestBase
{
[TestMethod]
public void TestMethod1()
{
}
}
在 TestBase 中我有 TestInitialize:
[TestInitialize]
public void Initialize()
{
SingletonClass.Initiate();
}
[TestCleanup]
public void Cleanup()
{
//Do some
}
SingletonClass 是测试中需要的静态 class。我需要启动一次,所以我这样做了:
public static class SingletonClass
{
public static bool IsInitiated { get; set; }
public static void Initiate()
{
if (!IsInitiated)
{
IsInitiated = true;
//Do some
Thread.Sleep(5000);
}
}
}
当我 运行 测试一个项目时它工作正常,但是当我 运行 全部启动它时它启动了 3 次(耗时 15 秒)。当我 运行 所有测试时,有什么办法只 运行 它一次吗?
类 能够拥有一个仅在首次引用 class 时调用的构造函数。
public static class SingletonClass
{
static SingletonClass()
{
IsInitiated = true;
//Do some
Thread.Sleep(5000);
}
}
根据您的测试运行器,您可能会为每个测试项目获得一个新流程。因此,单例确实被实例化了三次,每个进程一次。
您可以通过告诉 nunit 只对所有项目使用一个进程来解决这个问题:
nunit3-console.exe MyProject.dll --agents=1
编辑:对于 vstest,您可以设置 MaxCpuCount
参数。有关详细信息,请参阅 docs:
<MaxCpuCount>1</MaxCpuCount>
您在 3 个并行使用者之间存在共享状态问题。您无法像 Ben 解释的那样控制 vstests 如何创建进程。
执行此操作的唯一方法是将 SingletonClass 初始化移动到它自己的进程中,并让其他 3 个测试项目与该单独的进程通信。这将确保它只发生一次,无论 vstest 创建了多少个进程。
当然,只有在初始化非常昂贵的情况下才值得这样做。
通常您应该避免在测试之间共享状态。它使它们变脆。
恕我直言,每个测试都应定义使用的资源。这样,先前的测试就不会破坏当前的测试。但是如果你想要这种情况发生,你可以使用单例模式。喜欢:
public class MyClass
{
private static readonly MyClass _myClass = new MyClass();
private MyClass()
{
// Initialize your class here
}
public static MyClass Instance
{
get => _myClass;
}
}
静态值应该在多个单元测试中保持有效。
终于找到了解决办法。我使用 ILRepack 将所有项目合并到一个新项目 (AllTests) 中:
<!-- ILRepack -->
<Target Name="ILRepack" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<PropertyGroup>
<WorkingDirectory>$(OutputPath)</WorkingDirectory>
</PropertyGroup>
<ItemGroup>
<InputAssemblies Include="$(OutputPath)MainTest.dll" />
<InputAssemblies Include="$(OutputPath)FIrst.dll" />
<InputAssemblies Include="$(OutputPath)Second.dll" />
<InputAssemblies Include="$(OutputPath)Third.dll" />
</ItemGroup>
<Message Text="MERGING: @(InputAssemblies->'%(Filename)') into $(OutputAssembly)" Importance="High" />
<ILRepack OutputType="$(OutputType)" Internalize="false" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
</Target>
<!-- /ILRepack -->
现在,我可以 运行 所有测试都使用 vstest.console.exe:
vstest.console.exe AllTests.dll
或者我可以 运行 来自 visual studio:
单身人士class 只按时启动。我不知道它是如何产生负面影响的,但目前它运行良好
我有三个测试项目。所有这些都引用自模型项目:
我在模型项目中创建了 TestBase class 并将其用作所有测试 class 的基础 class。 继承看起来像这样:
[TestClass]
public class UnitTest1 : TestBase
{
[TestMethod]
public void TestMethod1()
{
}
}
在 TestBase 中我有 TestInitialize:
[TestInitialize]
public void Initialize()
{
SingletonClass.Initiate();
}
[TestCleanup]
public void Cleanup()
{
//Do some
}
SingletonClass 是测试中需要的静态 class。我需要启动一次,所以我这样做了:
public static class SingletonClass
{
public static bool IsInitiated { get; set; }
public static void Initiate()
{
if (!IsInitiated)
{
IsInitiated = true;
//Do some
Thread.Sleep(5000);
}
}
}
当我 运行 测试一个项目时它工作正常,但是当我 运行 全部启动它时它启动了 3 次(耗时 15 秒)。当我 运行 所有测试时,有什么办法只 运行 它一次吗?
类 能够拥有一个仅在首次引用 class 时调用的构造函数。
public static class SingletonClass
{
static SingletonClass()
{
IsInitiated = true;
//Do some
Thread.Sleep(5000);
}
}
根据您的测试运行器,您可能会为每个测试项目获得一个新流程。因此,单例确实被实例化了三次,每个进程一次。
您可以通过告诉 nunit 只对所有项目使用一个进程来解决这个问题:
nunit3-console.exe MyProject.dll --agents=1
编辑:对于 vstest,您可以设置 MaxCpuCount
参数。有关详细信息,请参阅 docs:
<MaxCpuCount>1</MaxCpuCount>
您在 3 个并行使用者之间存在共享状态问题。您无法像 Ben 解释的那样控制 vstests 如何创建进程。
执行此操作的唯一方法是将 SingletonClass 初始化移动到它自己的进程中,并让其他 3 个测试项目与该单独的进程通信。这将确保它只发生一次,无论 vstest 创建了多少个进程。
当然,只有在初始化非常昂贵的情况下才值得这样做。
通常您应该避免在测试之间共享状态。它使它们变脆。
恕我直言,每个测试都应定义使用的资源。这样,先前的测试就不会破坏当前的测试。但是如果你想要这种情况发生,你可以使用单例模式。喜欢:
public class MyClass
{
private static readonly MyClass _myClass = new MyClass();
private MyClass()
{
// Initialize your class here
}
public static MyClass Instance
{
get => _myClass;
}
}
静态值应该在多个单元测试中保持有效。
终于找到了解决办法。我使用 ILRepack 将所有项目合并到一个新项目 (AllTests) 中:
<!-- ILRepack -->
<Target Name="ILRepack" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<PropertyGroup>
<WorkingDirectory>$(OutputPath)</WorkingDirectory>
</PropertyGroup>
<ItemGroup>
<InputAssemblies Include="$(OutputPath)MainTest.dll" />
<InputAssemblies Include="$(OutputPath)FIrst.dll" />
<InputAssemblies Include="$(OutputPath)Second.dll" />
<InputAssemblies Include="$(OutputPath)Third.dll" />
</ItemGroup>
<Message Text="MERGING: @(InputAssemblies->'%(Filename)') into $(OutputAssembly)" Importance="High" />
<ILRepack OutputType="$(OutputType)" Internalize="false" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
</Target>
<!-- /ILRepack -->
现在,我可以 运行 所有测试都使用 vstest.console.exe:
vstest.console.exe AllTests.dll
或者我可以 运行 来自 visual studio:
单身人士class 只按时启动。我不知道它是如何产生负面影响的,但目前它运行良好