2013-08-16 45 views
2

鉴于以下情况,是否适当使用起订量?我对“嘲笑”,“磕磕绊绊”,“伪装”等方面都很陌生,只是想把头围绕在它周围。在单元测试中正确使用最小起订量

我的理解是,这个模拟提供了一个已知的结果,所以当我使用它来测试这个服务时,服务反应是否正确?

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。

+2

测试对我来说看起来很好。用例的有效测试。 – labroo

+1

我建议的一件事就是你让测试名称代表正在测试的内容。让您在稍后再回来测试时更容易理解。所以,而不是“Test1”称之为“CannotCreateACustomerWithSameIdAsExistingCustomer” – Caleb

回答

3

我的理解是,这是模拟提供了一个已知结果的方式, 所以当我测试它使用这项服务,该服务正常反应?

这种说法是正确的 - 单元测试应该验证你正在测试的类(在这种情况下,CustomerService)是展示你想要的行为。它并不打算验证它的依赖性是否按预期运行(在这种情况下,IRepository<Customer>)。

您的测试很好* - 您正在设置IRepository的模拟并注入您的SystemUnderTest,并验证CustomerService.CreateCustomer()函数是否展示您期望的行为。

*测试的整体设置很好,但我对xUnit不熟悉,所以最后两行的语法对我来说是陌生的,但它看起来像是基于语义的正确。作为参考,你会做的最后两行NUnit的,像这样:

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

测试看起来好像没什么问题,模拟只是提供一个返回硬编码的答案只是为了测试一个假仓库,所以只有测试关心你正在测试的服务,不处理真实​​数据库或其他任何事情,因为你在这里没有测试它。

我只会在测试中添加一件更完整的东西。 当您在模拟上设置方法调用时,确保它们真的被测试系统调用。毕竟,该服务应该向回购商询问某个对象并且仅在某个返回值下抛出。起订量特别为此提供了一个语法:

repo.VerifyAll(); 

这样做是简单地检查你面前放置了设置与实际调用至少一次。这可以保护您免受错误的影响,即服务只是在不调用回购协议的情况下立即抛出异常(很容易在像您这样的示例中发现,但使用复杂的代码很容易错过呼叫)。通过该行,在测试结束时,如果您的服务没有调用请求列表的repo(并使用该特定参数集),那么即使异常被正确抛出,测试也会失败。

相关问题