繁体   English   中英

在单元测试中正确使用最小起订量

[英]Proper use of MOQ in a Unit Test

鉴于以下情况,这是否是最小起订量的正确使用? 我对“嘲笑”,“窃听”,“伪造”等等非常陌生,只是想把我的头缠住。

我的理解是,此模拟提供了已知的结果,因此当我使用该模拟测试该服务时,该服务是否能够正确响应?

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    IQueryable<T> Query();
}

public interface ICustomerService
{
    void CreateCustomer(Customer customer);
    Customer GetCustomerById(int id);
}

public class Customer
{
    public int Id { get; set; }

}

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer> customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        this.customerRepository = customerRepository;
    }

    public Customer GetCustomerById(int id)
    {
        return customerRepository.Query().Single(x => x.Id == id);
    }

    public void CreateCustomer(Customer customer)
    {
        var existingCustomer = customerRepository.Query().SingleOrDefault(x => x.Id == customer.Id);

        if (existingCustomer != null)
            throw new InvalidOperationException("Customer with that Id already exists.");

        customerRepository.Add(customer);
    }
}

public class CustomerServiceTests
    {
        [Fact]
        public void Test1()
        {
            //var repo = new MockCustomerRepository();
            var repo = new Mock<IRepository<Customer>>();
            repo.Setup(x => x.Query()).Returns(new List<Customer>() { new Customer() { Id = 1 }}.AsQueryable());

            var service = new CustomerService(repo.Object);

            Action a = () => service.CreateCustomer(new Customer() { Id = 1 });

            a.ShouldThrow<InvalidOperationException>();

        }
    }

我正在使用xUnit,FluentAssertions和MOQ。

我的理解是,此模拟提供了已知的结果,因此当我使用该模拟测试该服务时,该服务是否能够正确响应?

该声明是正确的-单元测试应验证您正在测试的类(在本例中为CustomerService )是否表现出所需的行为。 它并不是要验证其依赖项是否按预期方式运行(在这种情况下,是IRepository<Customer> )。

您的测试很好*-您正在为IRepository设置模拟并将其注入到SystemUnderTest中,并验证CustomerService.CreateCustomer()函数是否表现出预期的行为。

*测试的总体设置很好,但是我对xUnit并不熟悉,所以最后两行的语法对我来说是陌生的,但根据语义看来它是正确的。 作为参考,您可以在NUnit中执行最后两行,如下所示:

Assert.Throws<InvalidOperationException>(() => service.CreateCustomer(...));

该测试对我来说看起来不错,该模拟程序仅提供了一个伪造的存储库,该存储库仅为该测试返回了一个硬编码的答案,因此该测试仅关心您正在测试的服务,而不处理真实​​数据库或任何其他内容,因为您不在这里进行测试。

我只会在测试中添加一件事以使其更加完整。 在模拟程序上设置方法调用时,请确保被测试的系统确实调用了它们 毕竟,该服务应该向存储库询问某些对象,并仅在某个返回值下抛出。 Moq特别为此提供了一种语法:

repo.VerifyAll();

这样做只是检查您之前放置的设置是否至少实际被调用过一次。 这可以保护您避免错误,即服务不立即调用该仓库就立即抛出异常(在您的示例中很容易发现,但是使用复杂的代码很容易错过一个调用)。 通过该行,在测试结束时,如果您的服务没有调用存储库的清单(以及特定的参数集),即使正确抛出了异常,测试也将失败。

暂无
暂无

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

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