简体   繁体   English

我需要多个断言吗? xUnit测试

[英]Do I need multiple assert? xUnit Test

this is my first time writing unit test, and I just have a few questions. 这是我第一次编写单元测试,但我有几个问题。 Im using in memory database to test my services and I'am wondering if I'm doing it correctly. 我在内存数据库中使用它来测试我的服务,我想知道自己是否做对了。 My first question is do I need multiple assert on all of my service call? 我的第一个问题是我是否需要对所有服务调用都使用多个断言? like do i need assert for InsertProduct ? 像我需要为InsertProduct断言吗? Second, Am I over testing this for using new instance of context on every service call? 其次,我是否在每个服务调用上都使用新的上下文实例方面对此进行了过度测试?

[Fact]
public void ProductService_DeleteProduct_Test()
{
    // arrange
    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
        .UseInMemoryDatabase(databaseName: "ProductService_DeleteProduct_Test")
        .Options;

    var product = new Product() { Id = Guid.NewGuid(), Name = "Product"};

    // act
    // insert
    using (var context = new ApplicationDbContext(options))
    {
        var service = new Service(context);
        service.ProductService.InsertProduct(product);
    }

    // delete
    using (var context = new ApplicationDbContext(options))
    {
        var service = new Service(context);
        service.ProductService.DeleteProducts(new List<Guid> { product.Id });
    }

    // assert
    using (var context = new ApplicationDbContext(options))
    {
        var service = new Service(context);
        Assert.Equal(0, service.ProductService.GetAllProducts().Count);
    }
}

Answering your first question, I'd say no. 回答您的第一个问题,我不会。 Since this is a unit test and you're testing the delete specifically. 由于这是单元测试,因此您正在专门测试删除。 I consider the insert part of the setup since you're getting the system into a state where you want to test the delete. 我考虑了安装程序的插入部分,因为您正在使系统进入要测试删除的状态。 To Zoran Horvat's point, if you can, put a row in the database via some means other than the service itself. 就Zoran Horvat而言,如果可以的话,可以通过服务本身以外的其他方式在数据库中放置一行。

To answer your second question, it seems unnecessary to have three using blocks where you're new'ing up the service three times. 要回答您的第二个问题,似乎没有必要在三个您刚开始使用该服务的地方使用三个使用块。 I'd put the insert, delete, and assert in the same using, making use of one instance of the SUT, or service. 我将使用SUT或服务的一个实例,将插入,删除和断言以相同的方式使用。

However, if you have multiple tests that all require there to be a row in the database, consider moving the insert into a SetUp method with the [SetUp] attribute that every test can call before hand. 但是,如果您有多个测试,所有这些测试都要求数据库中有一行,请考虑将插入内容移到具有[SetUp]属性的SetUp方法中,每个测试都可以事先调用该属性。 In that case, you'd be using multiple instances of the context. 在这种情况下,您将使用上下文的多个实例。

I would make an objection on the structure of your test. 我会对您的考试结构提出异议。 Namely, you are using the service (production code) to prepare the underlying database. 即,您正在使用服务(生产代码)准备基础数据库。 And you are also using the production code to make the assertion. 而且您还使用生产代码进行断言。

If any part of the production code is incorrect, this test will fail. 如果生产代码的任何部分不正确,则此测试将失败。 However, this test is designed to assert that the delete feature is doing right. 但是,此测试旨在断言删除功能运行正常。

Therefore, I would rewrite entire test in the following way: 因此,我将以以下方式重写整个测试:

[Fact]
public void ProductService_DeleteProduct_Test()
{
    // arrange
    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
        .UseInMemoryDatabase(databaseName: "ProductService_DeleteProduct_Test")
        .Options;

    var product = new Product() { Id = Guid.NewGuid(), Name = "Product"};

    // Insert object using other means, i.e. direct INSERT statement

    // act
    using (var context = new ApplicationDbContext(options))
    {
        var service = new Service(context);
        service.ProductService.DeleteProducts(new List<Guid> { product.Id });
    }

    // assert
    // Execute SELECT COUNT(*) instruction to fetch previously existing row
    Assert.Equal(0, rowsCount);
}

In this way, you will only touch production code in the acting part of the test. 这样,您将仅在测试的执行部分中触摸生产代码。 That is the part in which you are using the service object to delete an object from the database. 那就是使用服务对象从数据库中删除对象的部分。

Subsequent assertion is done against a scalar value count which is fetched as the result of a raw SELECT statement executed directly on the storage. 随后对标量值count进行断言,该标量值count是直接在存储器上执行的原始SELECT语句的结果。

Bottom line is that none of the parts of your test are now depending on correctness of the production code, except the DeleteProducts method which is in fact the method under test. 最重要的是,除了DeleteProducts方法(实际上是被测试的方法)外,测试的所有部分现在都不取决于生产代码的正确性。

And, consequently, the answer to your question is that there is only one assertion to write in this test. 因此,对于您的问题的答案是,在此测试中只需编写一个断言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM