单元测试可以通过接受布尔值作为开关来执行双重任务吗?或者我应该写两个单独的测试来复制测试代码

本文关键字:测试 我应该 两个 复制 代码 单独 或者 布尔值 可以通过 开关 任务 | 更新日期: 2023-09-27 18:21:59

我有一个方法,它的操作依赖于它的依赖项,如下所示。做单元测试仍然有价值吗?因为单元测试不是测试任何业务逻辑,而是通过模拟测试。

以下单元测试:

请注意,该方法的操作由测试设置的expectedCustomerValidality决定。大多数情况下,逻辑由模拟(例如Setup(c => c.IsValid()).

        [Test]
        [TestCase(true)]
        [TestCase(false)]
        public void AddCustomer(bool expectedCustomerValidality)
        {
           //using Moq
            companyRepositoryMock.Setup(c => c.GetById(It.IsAny<int>())).Returns(new Company());          
            customerValidatorMock.Setup(c => c.IsValid(It.IsAny<Customer>())).Returns(expectedCustomerValidality);
            var customer = new Customer
                               {
                                   Firstname = "firstName",
                                   Surname = "surname",
                                   Company = new Company { Id = 1 }
                               };
            var addCustomer = customerServiceSut.AddCustomer(customer);
            Assert.AreEqual(expectedCustomerValidality,addCustomer);
        }

生产代码如下:

 public class CustomerService : ICustomerService
    {
        private ICompanyRepository companyRepository;
        private ICustomerRepository customerRepository;
        private ICustomerValidator customerValidator;
        public CustomerService(ICompanyRepository companyRepository, ICustomerRepository customerRepository, ICustomerValidator customerValidator)
        {
            this.companyRepository = companyRepository;
            this.customerRepository = customerRepository;
            this.customerValidator = customerValidator;
        }
        public bool AddCustomer(Customer customer)
        {           
            customer.Company = companyRepository.GetById(customer.Company.Id); ;
            if (customerValidator.IsValid(customer))
            {
                customerRepository.AddCustomer(customer);
                return true;
            }
            return false;
        }
}

问题:

  • AddCustomer()是否需要单元测试
  • 如果是,当前单元测试的执行方式是否正确?

    1如果没有,单元测试的正确方法是什么?

单元测试可以通过接受布尔值作为开关来执行双重任务吗?或者我应该写两个单独的测试来复制测试代码

我不喜欢这样。原因如下:您的测试方法名称应该反映测试中的方法、测试的先决条件以及您期望的测试结果:

public bool AddCustomer_CustomerIsValid_ShouldReturnTrue()
public bool AddCustomer_CustomerIsInvalid_ShouldReturnFalse()

现在,如果您愿意,可以将核心测试逻辑重构为自己的方法,以消除代码重复,然后从上面的两个方法中调用该方法。但是重构后的方法不是一个测试用例;它只是实际测试用例的辅助方法。

示例:

[Test]
public void AddCustomer_CustomerIsValid_ShouldReturnTrue()
{
    var result = AddCustomerTest(true);
    Assert.IsTrue(result);
}
[Test]
public void AddCustomer_CustomerIsInvalid_ShouldReturnFalse()
{
    var result = AddCustomerTest(false);
    Assert.IsFalse(result);
}
public void AddCustomerTest(bool expectedCustomerValidality)
{
   //using Moq
    companyRepositoryMock.Setup(c => c.GetById(It.IsAny<int>())).Returns(new Company());          
    customerValidatorMock.Setup(c => c.IsValid(It.IsAny<Customer>())).Returns(expectedCustomerValidality);
    var customer = new Customer
    {
        Firstname = "firstName",
        Surname = "surname",
        Company = new Company { Id = 1 }
    };
    var result= customerServiceSut.AddCustomer(customer);
    return result;
}

AddCustomer需要测试,因为它执行业务逻辑——它检索并设置公司,验证数据,将数据添加到存储库,并返回结果。

你的测试几乎是正确的。我会更具体一点,来验证所有的业务逻辑:

[Test]
[TestCase(true)]
[TestCase(false)]
public void AddCustomer(bool isCustomerValid)
{
     //arrange
     //NOTE!!! create the mocks with MockBehavior.Strict
     //that way the test will fail if a call is made w/o setup
     const long testCompanyId = 100;
     var testCompany = new Company{ Id = testCompanyId };
     companyRepository.Setup(r => r.GetById(testCompanyId))
          .Returns(testCompany);
     var testCustomer = new Customer
                   {
                        Firstname = "firstName",
                        Surname = "surname",
                        Company = new Company { Id = testCompanyId }
                   };
     customerValidatorMock.Setup(c => c.IsValid(It.Is<Customer>(c => c == testCustomer && c.Company == testCompany)).Returns(isCustomerValid);
     if (isCustomerValid)
     {
          customerRepository.Setup( r => r.AddCustomer(testCustomer) ). Verifiable();
     }
     //act        
     var addCustomerResult = customerServiceSut.AddCustomer(testCustomer);
     //assert
     Assert.AreEqual(isCustomerValid, addCustomerResult);
     cutomerRepository.VerifyAll();
}

上面的测试将测试服务方法的所有功能,包括是否通过id获取公司,以及是否使用获取的id。此外,它将验证客户是否已添加,是否有效。如果添加了无效的客户,则测试将失败(因为customerRepository是使用MockBehavior.Strict创建的,并且不会执行设置)。