在单元测试中自动化依赖注入

本文关键字:依赖 注入 自动化 单元测试 | 更新日期: 2023-09-27 18:11:04

我有一个文件夹,其中的程序集都包含某个接口的实现(每个程序集都不同)。我已经为该接口编写了一些单元测试,并希望在每个实现上自动执行运行接口测试的任务。

我有一个我不喜欢的可行的解决方案:

  • 在实际的测试类中编写代码来加载(程序集)并实例化实现,将它们存储在列表中

  • 编写每个测试来循环遍历实现列表,在每个实现上运行它的断言。

我想要的是在一个实现上运行所有测试,然后移动到下一个实现上再次运行所有测试,以此类推。我的想法是找到一种方法来做这样的事情(编程):

  • 加载程序集并实例化实现-像以前一样,但不在测试类中。
  • 创建一个测试类的实例,注入下一个实现。
  • 运行测试。
  • 移动到下一个实现,重复这个过程。

(我意识到我可以在文件系统中变换文件-例如将程序集放在一个位置>运行加载一个实现的测试>用下一个实现替换程序集,然后重复该过程。但是,如果可能的话,我想要一些不那么粗糙的东西。

我一直在寻找nUnit测试运行器(控制台等)的捷径,但到目前为止还没有找到。有没有人知道,如果有一种方法来实现我想要使用nUnit或任何其他测试套件,可以通过编程控制?或者也许有另一种方法可以满足上面的"我想要什么"标准?

在单元测试中自动化依赖注入

我最终使用了NUnit的SuiteAttribute。

这种方法需要创建一个"伞形类",如下所示:

namespace Validator {
    public class AllTests {
        [Suite]
        public static IEnumerable Suite {
            get {
                var directory = @"[ImplementationAssembliesPath]";
                var suite = new ArrayList();
                // GetInstances is a method responsible for loading the
                // assemblys and instantiating the implementations to be tested.
                foreach (var instance in GetInstances(directory)) {
                    suite.Add(GetResolvedTest(instance));
                }
                return suite;
            }
        }
        // This part is crucial - this is where I get to inject the 
        // implementations to the test.
        private static Object GetResolvedTest(ICalculator instance) {
            return new CalculatorTests {Calculator = instance};
        }
        [...]
}

注意,测试类有一个属性,用于注入我想要的实现。我之所以选择属性注入,是因为测试运行者通常不喜欢默认构造函数。然而,我不得不从实际的测试类(此处省略)中删除TestFixtureAttribute ,以避免混淆Console-Runner要运行什么。

然后我创建了一个简单的控制台应用程序来运行带有/fixture参数的NUnit控制台运行器:
namespace TestRunner {
    using System;
    using NUnit.ConsoleRunner;
    internal class Program {
        private static void Main(String[] args) {
            var testDllPath = @"[TestAssemblyPath]/Validator.dll";
            var processArgument = @"/process=Separate";
            var domainArgument = @"/domain=Multiple";
            var runtimeArgument = @"/framework=4.5";
            var shadowArgument = @"/noshadow";
            var fixtureArgument = String.Format(@"/fixture={0}", "[Namespace].AllTests");
            Runner.Main(new[] {
                testDllPath,
                processArgument,
                domainArgument,
                runtimeArgument,
                shadowArgument,
                fixtureArgument
            });
            Console.ReadLine();
        }
    }
}

我仍然很想听听你对这件事的看法,以及其他解决方案。

如果你想测试一组固定的程序集,你不需要做一些花哨的事情,比如移动程序集或指示测试运行程序。

与普通类一样,您可以对单元测试类使用继承。我建议您创建一个抽象基类来完成测试该接口实现的繁重工作。对于接口的每个实现,都可以创建一个继承基类的新类。

基类可以像这样:

public class BaseMyInterfaceImplementationTest 
{
    protected MyInterface ClassUnderTest;
    //Add your tests here with the [Test] attribute:
    [Test]
    public void TestScenario1()
    {
        //do your test on ClassUnderTest
    }   
}

和这样的派生类:

[TestFixture]
public class Implementation1Tests : BaseMyInterfaceImplementationTest 
{
    [SetUp]
    public void BaseTestInitialize()
    {
        ClassUnderTest = new Implementation1();
    }
}