【问题标题】:Automating Dependency Injection in Unit Testing在单元测试中自动化依赖注入
【发布时间】:2015-11-30 05:57:52
【问题描述】:

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

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

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

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

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

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

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

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

【问题讨论】:

  • 您可能需要考虑使用TestCaseSource 属性来提供您要测试的类的类型/实例。您需要加载程序集等,但 NUnit 会为您处理其余的管道。 nunit.org/index.php?p=testCaseSource&r=2.5.9
  • TestCaseSource 是一个选项,我同意,但不会实现为一个实现运行每个测试,然后继续下一个实现,重复该过程的目标 .由于未能通过实施IAddinISuiteBuilder 获得好的解决方案,我目前正在研究看起来很有希望的SuiteAttribute

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


【解决方案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();
    }
}

【讨论】:

  • 这如何有助于为每个实现运行一次所有测试(来自程序集,它们不是固定的集合,而是需要在运行时加载)?
  • @OskarLindberg 你是对的,我提出的解决方案只有在你有一组固定的实现时才有效。
【解决方案2】:

我最终使用了 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();
        }

    }

}

我仍然很想听听您对此以及替代解决方案的意见。

【讨论】:

    猜你喜欢
    • 2018-01-11
    • 2021-06-19
    • 1970-01-01
    • 2017-04-01
    • 2020-06-15
    • 2017-02-07
    • 1970-01-01
    相关资源
    最近更新 更多