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

时间:2015-09-04 06:57:16

标签: c# .net unit-testing dependency-injection nunit

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

我有一个我不喜欢的工作解决方案:

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

  • 编写每个测试以遍历实现列表,在每个测试上运行其断言。

我想要的是是在一个实现上运行所有测试,然后继续下一个再次运行所有测试,依此类推。我的想法是找到一种方法来做(像程序):

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

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

我一直在关注nUnit测试跑步者(控制台等)的捷径,但到目前为止还没有找到。有没有人知道是否有办法使用nUnit或任何其他可编程控制的测试套件来实现我想要的东西?或者也许还有另一种方式来实现这一切,这将满足我想要的"我想要的"以上标准?

2 个答案:

答案 0 :(得分:0)

我最终使用了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 Console-Runner:

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();
        }

    }

}

我仍然有兴趣听取您对此以及替代解决方案的意见。

答案 1 :(得分:-1)

如果你想测试一组固定的组件,你不必做像移动组件或指导测试跑步者这样的花哨的东西。

与普通类一样,您可以为单元测试类使用继承。我建议你创建一个抽象基类,它可以用来测试这个接口的实现。对于接口的每个实现,您可以创建一个继承自基类的新类。

基类看起来像这样:

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();
    }
}