2013-08-16 2 views
2

다음은 MOQ를 올바르게 사용 했습니까? 나는 "mocking", "stubbing", "faking"등등에 새롭고, 단지 내 머리를 감싸려고 노력합니다.단위 테스트에서 MOQ를 올바르게 사용하십시오.

이 모의는 알려진 결과를 제공한다는 것을 이해하기 때문에이 서비스를 사용하여이 서비스를 테스트하면 서비스가 제대로 반응합니까?

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

을 시험은 나에게 잘 보이는, 모의은 단지 테스트를위한 하드 답을 반환하는 가짜 저장소를 제공하므로 시험 만 테스트하고있는 서비스에 관심이 있으며, 실제 데이터베이스를 다루지 않습니다. 여기에서 테스트하지 않으므로.

테스트에 한 가지만 추가하면 더 완벽 해집니다. mock에서 메소드 호출을 설정할 때, 실제로 테스트중인 시스템에 의해 메소드 호출이 호출되었는지 확인하십시오. 결국, 서비스는 repo에 객체를 요청하고 특정 반환 값 아래서 만 throw해야합니다. 특히 Moq은 이에 대한 문법을 ​​제공합니다 :

repo.VerifyAll(); 

이것은 단지 한 번 이상 실제로 호출 된 설정을 확인하는 것입니다. 이렇게하면 서비스가 repo를 호출하지 않고도 예외를 즉시 throw하는 오류 (사용자와 같은 예제에서는 쉽게 찾을 수 있지만 복잡한 코드에서는 쉽게 누락 될 수 있음)에서 사용자를 보호 할 수 있습니다. 이 줄에서 테스트가 끝날 때 서비스가 목록을 요구하는 repo (및 해당 특정 매개 변수 집합)를 호출하지 않은 경우에도 예외가 제대로 throw 된 경우에도 테스트가 실패합니다.