我可以强制 MSTest 在每次测试运行时使用新进程吗?

问题描述 投票:0回答:4

我们使用 VS 2010 测试运行程序 (MSTest) 进行自动化功能测试。当我们从 Visual Studio 运行测试时,VS 创建一个名为 QTAgent32.exe 的进程,并在该进程中运行测试。

我们发现,当我们进行多次测试运行时,MSTest 将重用相同的 QTAgent32 进程 - 进程 ID 不会改变。这对我们来说是一个问题,因为我们正在测试的代码是对非托管 DLL 的 P/调用。 DLL 在进程的生命周期内只需要初始化一次。我们有一个 [AssemblyInitialize] 方法,但每次测试运行都会执行一次。如果我们执行多次测试运行,它将在同一进程中执行多次。

每次我们进行测试运行时,MSTest 都会创建一个新的应用程序域;但这些应用程序域都在同一个进程中。

所以我想知道:有没有办法告诉 Visual Studio 测试运行程序在每次运行测试时使用新进程?我查看了“.testsettings”配置,但没有看到任何相关内容。

.net visual-studio pinvoke mstest
4个回答
6
投票

不知道你想走多远,但一种解决方案可能是创建你的单元测试主机

http://technet.microsoft.com/fr-fr/query/bb166558

此链接显示了如何创建适配器,然后您也可以启动一个新的 Evertest 进程,创建管道通信并在测试后将其拆除。

我知道 MS 本身使用不同的主机在鼹鼠下运行测试

http://research.microsoft.com/en-us/projects/pex/molestutorial.pdf


1
投票

在阅读 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 的帮助!


0
投票

VS 2013 及更高版本现在在“测试”>“测试设置”>“保持测试执行引擎运行”下具有此设置。取消选中此选择将在每次运行时启动一个新引擎。


0
投票

我在 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]

重要注意事项:

  1. 它将创建测试类的新实例,因为我无法引用原始实例。因此,请尝试使方法尽可能自包含,

    [TestInitialize]
    等属性将不适用。

  2. 在 Visual Studio 测试主机中运行时,

    Tmds.ExecFunction
    不起作用,因为它找不到父进程(但从
    dotnet test
    可以正常工作)。我选择正常运行测试,但您应该修改属性以按照您想要的方式运行(例如,也许跳过测试而不是运行它)

© www.soinside.com 2019 - 2024. All rights reserved.