如何为运行时程序集位置编写测试用例

本文关键字:测试用例 位置 程序集 运行时 | 更新日期: 2023-09-27 17:59:23

这是我创建新应用程序实例的类:

public interface IApplicationInstanceProvider
{
    bool CreateNewProcess();
}
public class ApplicationInstanceProvider : IApplicationInstanceProvider
{
    public bool CreateNewProcess()
    {
        Process p = new Process();
        p.StartInfo.FileName = System.Reflection.Assembly.GetEntryAssembly().Location;
        return p.Start();
    }
}

这是我的测试用例:

[TestMethod]
public void TestMethodForAppInstance()
{
    IApplicationInstanceProvider provider = new ApplicationInstanceProvider();
    bool isCreated = provider.CreateNewProcess();
    Assert.AreEqual(isCreated,true);
}

问题是:在执行测试用例时,System.Reflection.Assembly.GetEntryAssembly()为null。但它在应用程序运行时运行良好。请帮忙!

如何为运行时程序集位置编写测试用例

您无法按原样测试您的类,因为您正在测试环境中执行一个未知的新进程。这是不可行的,因为:

  1. Assembly.GetEntryAssembly()将返回null
  2. 无论它返回什么,您都将执行那个过程,它可能是devenv.exechrome.exe或其他什么

CreateNewProcess()方法做很多事情:它确定要执行的程序的路径并运行它。此外,它的返回值告诉调用方是否启动了新的进程或现有进程已被重用。对于一个方法来说,太多的东西使得测试变得困难。幸运的是,至少有两种方法可以使代码可测试:创建一个专门的ApplicationInstanceProvider类进行测试,或者为其创建一个单独的类

让我们看看第一种方法:

public class ApplicationInstanceProvider : IApplicationInstanceProvider {
    public bool CreateNewProcess() {
        Process process = new Process();
        process.StartInfo.FileName = ResolveApplicationPath();
        return process.Start();
    }
    protected virtual string ResolveApplicationPath() {
        return System.Reflection.Assembly.GetEntryAssembly().Location;
    }
}

您将创建一个用于测试的派生类:

sealed class TestApplicationInstanceProvider : ApplicationInstanceProvider {
    protected override string ResolveApplicationPath() {
        // path to your assembly or a well-known executable executable
        // Like %WINDIR%'notepad.exe
        return "...";
    }
}

然后它会像这样在你的测试方法中使用:

[TestMethod]
public void TestMethodForAppInstance() {
    var provider = new TestApplicationInstanceProvider();
    bool isCreated = provider.CreateNewProcess();
    Assert.AreEqual(isCreated, true);
}

请注意,您不能测试Assembly.GetEntryAssembly(),但可以测试所有els。请注意,现在您正在测试是否创建了一个新的流程实例,但没有检查是否启动了一个;这将增加代码覆盖率,但实际上您几乎没有测试任何东西,因为对于可执行文件,Process.Start()将始终返回true(对于文档,运行进程可能会重用)。这就是为什么必须划分CreateNewProcess()响应(不仅为了清晰,而且为了测试)。测试后,不要忘记关闭清理方法中的流程实例!

让我们看看第二种方法:第二种方式稍微复杂一点,但更通用:

public interface IAssemblyResolver {
    string GetEntryAssemblyPath();
}
public sealed class DefaultAssemblyResolver : IAssemblyResolver {
    public string GetEntryAssemblyPath() {
        return System.Reflection.Assembly.GetEntryAssembly().Location;
    }
}
public class ApplicationInstanceProvider : IApplicationInstanceProvider {
    public ApplicationInstanceProvider(IAssemblyResolver resolver) {
        _resolver = resolver;
    }
    public bool CreateNewProcess() {
        Process process = new Process();
        process.StartInfo.FileName = _resolver.GetEntryAssemblyPath();
        return process.Start();
    }
    private readonly IAssemblyResolver _resolver;
}

现在您必须创建一个用于测试的模拟:

sealed class TestAssemblyResolver : IAssemblyResolver {
    public string GetEntryAssemblyPath() {
        // Return path of a well-known test application,
        // for example an "empty" console application. You can also
        // reuse it to, for example, return different error codes
        return Assembly.Load(...);
    }
}

测试方法:

[TestMethod]
public void TestMethodForAppInstance() {
    var resolver = new TestAssemblyResolver();
    var provider = new ApplicationInstanceProvider(resolver);
    bool isCreated = provider.CreateNewProcess();
    Assert.AreEqual(isCreated, true);
}

您的假冒应用程序可能是什么样子的?

static class Program {
    static int Main(string[] args) {
        if (args.Length == 0)
            return 0;
        return Int32.Parse(args[0]);
    }
}