在编写基于 .net MVC 的应用程序时,我一直在努力将自己转变为一种更受测试驱动的方法。我正在使用基于构造函数的注入(inject)进行所有依赖注入(inject)。到目前为止一切顺利,但我发现自己反复做某事,我想知道是否有更好的做法。
假设我想测试一个 Controller 。它依赖于工作单元(数据库)对象。很简单......我编写 Controller 以在其构造函数中获取该接口(interface),我的 DI 框架 (Ninject) 可以在运行时注入(inject)它。简单的。同时在我的单元测试中,我可以使用模型化的数据库对象手动构建我的 Controller 。我喜欢这样,我可以编写很多独立的独立测试来处理所有对象的构造和测试。
现在我继续前进并开始向我的 Controller 对象添加新的特性和功能。 Controller 现在有一个或两个以上的依赖项。我可以使用这 3 个依赖项编写更多测试,但我的旧测试都已损坏(无法编译),因为编译器会抛出一大堆错误,如下所示:
'MyProject.Web.Api.Controllers.MyExampleController' does not contain a constructor that takes 3 arguments
我一直在做的(闻起来很糟糕)是返回并更新我所有的单元测试,更改构造代码,并为我的旧测试不关心的所有新依赖项添加 null 参数,就像这样:
来自这里:
var controllerToTest = new MyExampleController(mockUOW.Object);
对此:
var controllerToTest = new MyExampleController(mockUOW.Object, null, null);
这让一切都可以编译并让我的测试再次运行,但我不喜欢返回并编辑大量旧测试只是为了更改对我的对象构造函数的调用的前景。
有没有更好的方法来编写单元测试(或者有更好的方法来编写类和进行 DI?)以便在添加新依赖项时它们不会全部中断?
最佳答案
您在单元测试时遇到了一个常见问题:代码重复导致大量重构开销。解决方案是尝试将被测对象的实例化限制在一个地方。如果可以,请尝试在测试的 TestInitialize
方法中执行此操作:
[TestInitialize]
public void Init()
{
this.mockUOW = new Mock<ISomeDependency>();
this.mock2 = new Mock<IAnotherDependency>();
this.mock3 = new Mock<IYetAnotherDependency>();
// Do initial set-up on your mocks
this.controllerToTest = new MyExampleController(this.mockUOW, this.mock2, this.mock3);
}
有时,这是不切实际的:在创建被测类的实例之前,您需要在每个测试中进行特定设置。在这种情况下,将创建对象的代码移动到一个命名良好的方法中,然后调用它:
[TestMethod]
public void MyTestMethod()
{
// Do any required set-up on mocks, etc.
this.CreateController();
}
private void CreateController()
{
this.controllerToTest = new MyExampleController(this.mockUOW, this.mock2, this.mock3);
}
现在,当依赖项添加到您的 Controller 之一时,您(希望如此)在您的测试中只有一个地方可以更新。
另请注意,CreateController
方法未命名为 CreateMyExampleController
。作为最佳实践,我尽量避免在特定于某些类或方法的测试中使用方法名称。在这里,例如,在方法中包含类名会添加另一个容易被忽略的重构依赖。
关于c# - 当我向 Controller 添加新的依赖项时单元测试中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25852470/