2015-01-17 3 views
4

Недавно я начал изучать, как писать модульные тесты, а также какую часть модуля тестировать на функциональность и что издеваться. Я использую NSubstitute как свою насмешливую структуру. Мой пример в основном вызывает класс repo, который затем делает веб-вызов WEB API внешней службе, то есть AddCreditCard, которая затем возвращает результат. Я создал 2 модульных теста для AddCreditCard, один для успеха и один для Fail. Я все еще не на 100% уверен, что все правильно делаю. Единичные тесты проходят, но я не уверен, что мои проверки сделаны на правильные данные ... Вся помощь и предложения приветствуются!Я правильно пишу свои модульные тесты? NUnit + NSubstitute

public interface IApiResponse<T> 
{ 
    HttpStatusCode StatusCode { get; set; } 
    T Result { get; set; } 
    string ErrorMessage { get; } 
    bool HasErrors { get; } 
} 

public interface ISignedRequest 
{ 
    void ConfigureSettings(SignedRequestSettings settings); 

    IApiResponse Post(string jsonData, Dictionary<string, string> parameters = null, 
     IOptionalHeaders optionalHeaders = null); 
} 


public class PaymentRepository 
{ 
    private readonly SignedRequestSettings _settings; 
    private readonly ISignedRequest _signedRequest; 

    public PaymentRepository(ISignedRequest signedRequest = null) 
    { 
     if (signedRequest == null) 
      _signedRequest = new SignedRequest(); 
     else 
      _signedRequest = signedRequest; 
    } 

    public IApiResponse AddCreditCard(CreditCard request) 
    { 
     var jsonData = 
      JsonConvert.SerializeObject(request); 

     string action = string.Format("customers/{0}/paymentmethods", request.ConnectId); 
     _settings.Url = string.Format("{0}{1}", String.Empty, action); 
     _signedRequest.ConfigureSettings(_settings); 

     return _signedRequest.Post(jsonData); 
    } 
} 

    [Test] 
    public void AddCreditCard_GivenValidCreditCard_ReturnsCreatedResult() 
    { 
     //Given 
     var apiResponse = Substitute.For<IApiResponse>(); 
     apiResponse.StatusCode = HttpStatusCode.Created; 

     var signedRequest = Substitute.For<ISignedRequest>(); 
     signedRequest.Post(Arg.Any<String>()).Returns(apiResponse); 

     var creditCard = Substitute.For<CreditCard>(); 
     creditCard.ConnectId = Guid.Parse("1fc1ad83-cd4e-4b68-bce6-e03ee8f47fb6"); 

     var repo = new PaymentRepository(signedRequest); 

     //When 
     var addCreditCardResponse = repo.AddCreditCard(creditCard); 

     //Then 
     signedRequest.Received(1).ConfigureSettings(Arg.Any<SignedRequestSettings>()); 
     signedRequest.Received(1).Post(Arg.Any<String>()); 

     Assert.AreEqual(HttpStatusCode.Created, addCreditCardResponse.StatusCode); 
    } 

[Test] 
    public void AddCreditCard_GivenInvalidCreditCard_ReturnsHasErrorsResult() 
    { 
     //Given 
     var apiResponse = Substitute.For<IApiResponse>(); 
     apiResponse.HasErrors.Returns(true); 
     apiResponse.ErrorMessage.Returns("Add credit card error message"); 

     var signedRequest = Substitute.For<ISignedRequest>(); 
     signedRequest.Post(Arg.Any<String>()).Returns(apiResponse); 

     var creditCard = Substitute.For<CreditCard>(); 
     creditCard.ConnectId = Guid.Parse("1fc1ad83-cd4e-4b68-bce6-e03ee8f47fb6"); 

     var repo = new PaymentRepository(signedRequest); 

     //When 
     var addCreditCardResponse = repo.AddCreditCard(creditCard); 

     //Then 
     signedRequest.Received(1).ConfigureSettings(Arg.Any<SignedRequestSettings>()); 
     signedRequest.Received(1).Post(Arg.Any<String>()); 

     Assert.AreEqual(apiResponse.HasErrors, addCreditCardResponse.HasErrors); 
     Assert.AreEqual(apiResponse.ErrorMessage, addCreditCardResponse.ErrorMessage); 
    } 
+0

На первом румянце они выглядят как большие юнит-тесты. Одно из предложений, которое я хотел бы использовать, - использовать определенные аргументы или [сопоставление аргументов] (http://nsubstitute.github.io/help/argument-matchers/) в ваших 'signedRequest.Received (1)' вызовах. Если эти значения не важны для того, что вы тестируете. –

ответ

2

Я думаю, что ваши тесты в основном в порядке, но есть некоторые бит, которые я задал бы. Оба ваших тестов эти строки в нижней части:

signedRequest.Received(1).ConfigureSettings(Arg.Any<SignedRequestSettings>()); 
signedRequest.Received(1).Post(Arg.Any<String>()); 

это действительно важно, чтобы те испытания, что эти методы были вызваны на вашем signedRequest заменителя? Я бы предположил, что это, вероятно, нет. Если бы эти вызовы не были сделаны, я бы утвердил, что ваш тест потерпел бы неудачу в любом случае (хотя это в какой-то мере стилистическое решение).

Во-вторых, я бы сказал, что вам не хватает одного или нескольких тестов (опять же число немного стилистично). Как бы то ни было, вы не проверяете информацию, которая подается на вызовыили Post на ваш signedRequest. Код вашего репозитория может просто делать _signedRequest.Post("some random string");, и ваш тест все равно пройдет. Я бы добавил еще один тест, который проверяет эти вызовы, чтобы убедиться, что запрос действительно отправлен правильно. Именно здесь будет иметь смысл валидация Received. Что-то вроде:

signedRequest.Received(1).ConfigureSettings(Arg.Is<SignedRequestSettings>(x=>x.Url == someHardCodedUrl)); 
signedRequest.Received(1).Post(someHardCodedJsonString); 
Смежные вопросы