我们使用 VS 2010 测试运行程序 (MSTest) 进行自动化功能测试。当我们从 Visual Studio 运行测试时,VS 创建一个名为 QTAgent32.exe 的进程,并在该进程中运行测试。
我们发现,当我们进行多次测试运行时,MSTest 将重用相同的 QTAgent32 进程 - 进程 ID 不会改变。这对我们来说是一个问题,因为我们正在测试的代码是对非托管 DLL 的 P/调用。 DLL 在进程的生命周期内只需要初始化一次。我们有一个 [AssemblyInitialize] 方法,但每次测试运行都会执行一次。如果我们执行多次测试运行,它将在同一进程中执行多次。
每次我们进行测试运行时,MSTest 都会创建一个新的应用程序域;但这些应用程序域都在同一个进程中。
所以我想知道:有没有办法告诉 Visual Studio 测试运行程序在每次运行测试时使用新进程?我查看了“.testsettings”配置,但没有看到任何相关内容。
不知道你想走多远,但一种解决方案可能是创建你的单元测试主机
http://technet.microsoft.com/fr-fr/query/bb166558
此链接显示了如何创建适配器,然后您也可以启动一个新的 Evertest 进程,创建管道通信并在测试后将其拆除。
我知道 MS 本身使用不同的主机在鼹鼠下运行测试
http://research.microsoft.com/en-us/projects/pex/molestutorial.pdf
在阅读 Wiktor 关于 FreeLibrary() 的评论后,我能够让这个工作正常工作。
我使用了由 Mike Stall 创建的这个类,它提供了 LoadLibrary、GetProcAddress 和 FreeLibrary 的包装器。这样,我可以在每次测试运行中加载一次库,调用必要的方法,然后在测试运行结束时释放库。
Mike Stall 的代码使用 Marshal.GetDelegateForFunctionPointer,它将非托管函数指针转换为托管委托类型。
我必须将 [DllImport] extern 声明替换为委托类型的声明。所以我转换了这个:
[DllImport("asesignal.dll")]
public static extern bool ASESDK_Initialize(string licenseCode);
对此:
public delegate bool ASESDK_Initialize(string licenseCode);
Mike Stall 的代码包含通用委托的示例(Action
我可以像这样动态加载DLL:
_ht = new UnmanagedLibrary(@"c:\windows\system32\asesignal.dll");
要调用函数,我这样做:
var function = _ht.GetUnmanagedFunction<ASESDK_Initialize>("ASESDK_Initialize");
function(licenseCode);
感谢 Wiktor 和 np-hard 的帮助!
VS 2013 及更高版本现在在“测试”>“测试设置”>“保持测试执行引擎运行”下具有此设置。取消选中此选择将在每次运行时启动一个新引擎。
我在 2023 年为 MSTest + .Net Core 创建了一个(实验性)解决方案
需要https://www.nuget.org/packages/Tmds.ExecFunction
public class OutOfProcessTestAttribute : TestMethodAttribute
{
private static readonly FunctionExecutor Executor = new FunctionExecutor(
o =>
{
o.StartInfo.RedirectStandardError = true;
o.OnExit = p =>
{
if (p.ExitCode != 0)
{
throw new Exception(p.StandardError.ReadToEnd());
}
};
});
public override TestResult[] Execute(ITestMethod testMethod)
{
var hostFilename = Process.GetCurrentProcess().MainModule.FileName;
if (hostFilename.EndsWith("/testhost") || hostFilename.EndsWith("\\testhost.exe"))
{
return base.Execute(testMethod);
}
try
{
var obj = Activator.CreateInstance(testMethod.MethodInfo.DeclaringType!);
Action action = (Action)testMethod.MethodInfo.CreateDelegate(typeof(Action), obj);
Executor.Run(action);
return new TestResult[1] { new() { Outcome = UnitTestOutcome.Passed } };
}
catch (Exception e)
{
return new TestResult[1] { new() { TestFailureException = e, Outcome = UnitTestOutcome.Failed } };
}
}
}
现在您可以将
[TestMethod]
替换为 [OutOfProcessTest]
重要注意事项:
它将创建测试类的新实例,因为我无法引用原始实例。因此,请尝试使方法尽可能自包含,
[TestInitialize]
等属性将不适用。
在 Visual Studio 测试主机中运行时,
Tmds.ExecFunction
不起作用,因为它找不到父进程(但从 dotnet test
可以正常工作)。我选择正常运行测试,但您应该修改属性以按照您想要的方式运行(例如,也许跳过测试而不是运行它)