且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在单元测试中处理多个模拟和断言

更新时间:2022-11-17 20:56:29

首先,每个测试应该只有一个断言(除非另一个验证了真实的断言)如果您想断言列表的所有元素都是不同的,您可能希望首先断言该列表不为空.否则,您可能会得到误报.在其他情况下,每个测试应该只有一个断言.为什么?如果测试失败,它的名称会准确地告诉您出了什么问题.如果您有多个断言并且第一个失败,您不知道其余的是否正常.您只知道出了点问题".

First of all, each test should only have one assertion (unless the other validates the real one) e.q. if you want to assert that all elements of a list are distinct, you may want to assert first that the list is not empty. Otherwise you may get a false positive. In other cases there should only be one assert for each test. Why? If the test fails, it's name tells you exactly what is wrong. If you have multiple asserts and the first one fails you don't know if the rest was ok. All you know than is "something went wrong".

您说您不想在 10 个测试中设置所有模拟/存根.这就是为什么大多数框架为您提供在每次测试之前运行的 Setup 方法.在这里,您可以将大部分模拟配置放在一个地方并重复使用.在 NUnit 中,您只需创建一个方法并使用 [SetUp] 属性对其进行修饰.

You say you don't want to setup all mocks/stubs in 10 tests. This is why most frameworks offer you a Setup method which runs before each test. This is where you can put most of your mocks configuration in one place and reuse it. In NUnit you just create a method and decorate it with a [SetUp] attribute.

如果要测试具有不同参数值的方法,可以使用 NUnit 的 [TestCase] 属性.这非常优雅,您不必创建多个相同的测试.

If you want to test a method with different values of a parameter you can use NUnit's [TestCase] attributes. This is very elegant and you don't have to create multiple identical tests.

现在让我们谈谈有用的工具.

Now lets talk about the useful tools.

AutoFixture 这是一个了不起且非常强大的工具,它允许您创建一个类的对象需要多个依赖.它使用虚拟模拟自动设置依赖项,并允许您仅手动设置特定测试中需要的依赖项.假设您需要为 UnitOfWork 创建一个模拟,它将 10 个存储库作为依赖项.在您的测试中,您只需要设置其中之一.Autofixture 允许您创建那个 UnitOfWork,设置一个特定的存储库模拟(或更多,如果您需要).其余的依赖项将使用虚拟模拟自动设置.这为您节省了大量无用的代码.它有点像用于测试的 IOC 容器.

AutoFixture this is an amazing and very powerful tool that allows you to create an object of a class which requires multiple dependencies. It setups the dependencies with dummy mocks automatically, and allows you to manually setup only the ones you need in a particular test. Say you need to create a mock for UnitOfWork which takes 10 repositories as dependencies. In your test you only need to setup one of them. Autofixture allows you to create that UnitOfWork, setup that one particular repository mock (or more if you need). The rest of the dependencies will be set up automatically with dummy mocks. This saves you a huge amount of useless code. It is a little bit like an IOC container for your test.

它还可以为您生成带有随机数据的假对象.所以等式EntityModel.Document 的整个初始化就只有一行

It can also generate fake objects with random data for you. So e.q. the whole initialization of EntityModel.Document would be just one line

var repoResult = _fixture.Create<EntityModel.Document>();

特别看看:

  • 创建
  • 冻结
  • AutoMock 自定义

在这里你会找到我的回答,解释如何使用 AutoFixture.

Here you will find my answer explaining how to use AutoFixture.

语义比较 教程 这将帮助您在比较不同类型对象的属性时避免多个断言.如果属性具有相同的名称,它几乎会自动使用.如果没有,您可以定义映射.它还会准确地告诉您哪些属性不匹配并显示它们的值.

SemanticComparison Tutorial This is what will help you to avoid multiple assertions while comparing properties of objects of different types. If the properties have the same names it will to it almost automatically. If not, you can define the mappings. It will also tell you exactly which properties do not match and show their values.

Fluent assertions 这只是为您提供了一种更好的断言方式.而不是

Fluent assertions This just provides you a nicer way to assert stuff. Instead of

Assert.AreEqual(repoResult.Message, savedDocument.Message);

你可以做到

repoResult.Message.Should().Be(savedDocument.Message);

总结一下.这些工具将帮助您用更少的代码创建测试,并使它们更具可读性.深入了解他们需要时间.尤其是 AutoFixture,但是当您这样做时,它们将成为您添加到测试项目中的第一件事 - 相信我:).顺便说一句,它们都可以从 Nuget 获得.

To sum up. These tools will help you create your test with much less code and will make them much more readable. It takes time to get to know them well. Especially AutoFixture, but when you do, they become first things you add to your test projects - believe me :). Btw, they are all available from Nuget.

还有一个提示.如果您在测试类时遇到问题,通常表明架构不好.解决方案通常是从有问题的类中提取较小的类.(Single Responsibility Principal) 比你可以轻松测试业务逻辑的小类.并轻松测试原始类与它们的交互.

One more tip. If you have problems with testing a class it usually indicates a bad architecture. The solution usually is to extract smaller classes from the problematic class. (Single Responsibility Principal) Than you can easily test the small classes for business logic. And easily test the original class for interactions with them.