在单元测试中使用DI容器 [英] Using DI container in unit tests

查看:97
本文介绍了在单元测试中使用DI容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在相当大的应用中,我们一直在成功使用Simple Injector。我们一直在对所有生产类使用构造函数注入,并配置Simple Injector来填充所有内容,而所有内容都是桃花心木。

We've been using Simple Injector with good success, in a fairly substantial application. We've been using constructor injection for all of our production classes, and configuring Simple Injector to populate everything, and everything's peachy.

尽管如此,我们并未使用Simple用于管理我们的单元测试的依赖关系树的注入器。取而代之的是,我们一直在手动更新所有东西。

We've not, though, used Simple Injector to manage the dependency trees for our unit tests. Instead, we've been new'ing up everything manually.

我花了几天的时间进行主要的重构,几乎所有的时间都花在修复上面这些手动构建的依赖树在我们的单元测试中。

I just spent a couple of days working through a major refactoring, and nearly all of my time was in fixing these manually-constructed dependency trees in our unit tests.

这让我想知道-是否有人使用任何模式来配置在单元测试中使用的依赖树?至少对我们来说,在我们的测试中,我们的依赖关系树往往相当简单,但是其中有很多。

This has me wondering - does anyone have any patterns they use to configure the dependency trees they use in unit tests? For us, at least, in our tests our dependency trees tend to be fairly simple, but there are a lot of them.

任何人都有一种方法来管理这些依赖关系树。 ?

Anyone have a method they use to manage these?

推荐答案

对于真正的单元测试(即那些仅测试一个类并模拟其所有依赖项的测试),它不会使用DI框架没有任何意义。在这些测试中:

For true unit tests (i.e. those which only test one class, and mock all of its dependencies), it doesn't make any sense to use a DI framework. In these tests:


  • 如果您发现对于 new 使用您创建的所有模拟创建类的实例,一种有用的策略是创建所有模拟,并在Setup方法中为被测对象创建实例(这些都可以是私有实例)字段),然后每个测试的排列区域只需要在需要模拟的方法上调用相应的 Setup()代码即可。这样,每个测试类最终只能得到一个 new PersonController(...)语句。

  • 如果需要要创建许多域/数据对象,创建以合理值开头的Builder对象进行测试非常有用。因此,与其在整个代码中调用大量伪造的值,而不是在整个代码中调用大的构造函数,不如说是直接调用,例如 var person = new PersonBuilder()。Build(),可能只有几个链接方法调用您在该测试中特别关心的数据。您可能也对 AutoFixture 感兴趣,但是我从未使用过它,因此无法担保。

  • if you find that you have a lot of repetitive code for newing up an instance of your class with all the mocks you've created, one useful strategy is to create all of your mocks and create the instance for the subject-under-test in your Setup method (these can all be private instance fields), and then each individual test's "arrange" area just has to call the appropriate Setup() code on the methods it needs to mock. This way, you end up with only one new PersonController(...) statement per test class.
  • if you're needing to create a lot of domain/data objects, it's useful to create Builder objects that start with sane values for testing. So instead of invoking a huge constructor all over your code, with a bunch of fake values, you're mostly just calling, e.g., var person = new PersonBuilder().Build(), possibly with just a few chained method calls for pieces of data that you specifically care about in that test. You may also be interested in AutoFixture, but I've never used it so I can't vouch for it.

如果您正在编写 integration 测试,则需要在其中测试系统的多个部分之间的交互,但是您需要仍然需要能够模拟特定的部分,请考虑为您的服务创建Builder类,因此您可以说,例如 var personController =新的PersonControllerBuilder.WithRealDatabase(connection).WithAuthorization(新的AllowAllAuthorizationService())。Build()

If you're writing integration tests, where you need to test the interaction between several parts of the system, but you still need to be able to mock specific pieces, consider creating Builder classes for your services, so you can say, e.g. var personController = new PersonControllerBuilder.WithRealDatabase(connection).WithAuthorization(new AllowAllAuthorizationService()).Build().

如果您要编写端到端或方案测试,而您需要在其中测试整个系统,则可以使用真实产品所使用的相同配置代码来设置DI框架。您可以略微更改配置,以更好地以编程方式控制诸如登录哪个用户等之类的事情。您仍然仍然可以利用创建的其他构建器类来构建数据。

If you're writing end-to-end, or "scenario" tests, where you need to test the whole system, then it makes sense to set up your DI framework, leveraging the same configuration code that your real product uses. You can alter the configuration slightly to give yourself better programmatic control over things like which user is logged in and such. You can still leverage the other builder classes you've created for constructing data, too.

var user = new PersonBuilder().Build();
using(Login.As(user))
{
     var controller = Container.Get<PersonController>();
     var result = controller.GetCurrentUser();
     Assert.AreEqual(result.Username, user.Username)
}

这篇关于在单元测试中使用DI容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆