我最近开始学习如何编写单元测试,以及测试功能和模拟内容的单元的哪个部分。我正在使用NSubstitute作为我的模拟框架。我的示例基本上调用了一个repo类,然后对外部服务进行WEB API Web调用,即:AddCreditCard,然后返回结果。我为AddCreditCard创建了2个单元测试,一个用于Success,另一个用于Fail。我仍然不能100%确定我正在做所有这些。单元测试正在通过,但我不确定我的Asserts是否在正确的数据上完成...欢迎所有帮助和建议!
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 :(得分:2)
我认为你的测试基本上没问题,但我会质疑一些问题。你的两个测试都在底部有这些行:
signedRequest.Received(1).ConfigureSettings(Arg.Any<SignedRequestSettings>());
signedRequest.Received(1).Post(Arg.Any<String>());
对于那些在signedRequest
替代品上调用这些方法的测试真的很重要吗?我建议它可能不是。如果不进行这些调用,我认为你的测试无论如何都会失败(尽管这在某种程度上是一种风格决定)。
我要说的第二件事是你缺少一个或多个测试(这个数字有点风格)。就目前而言,您没有验证提供给ConfigureSettings
替代品上的Post
或signedRequest
来电的信息。您的存储库代码可能只是_signedRequest.Post("some random string");
,您的测试仍然会通过。我将添加另一个验证这些调用的测试,以确保实际正确发送请求。这是Received
验证有意义的地方。类似的东西:
signedRequest.Received(1).ConfigureSettings(Arg.Is<SignedRequestSettings>(x=>x.Url == someHardCodedUrl));
signedRequest.Received(1).Post(someHardCodedJsonString);