[英]Unit Test Assert against end result or verifying whether the parameters were called using Moq
以下是我要測試的課程(Class1),但是我對單元測試不完全滿意。 請參見下面的代碼示例。
被測系統
public interface IRepository {
string GetParameter(int id);
}
public class Repository {
public string GetParameter(int id) {
return "foo";
}
}
public class ErrorInfo {
public string ErrorCodes { get; set; }
}
public interface IErrorProvider {
ErrorInfo BuildErrorMessage(string errorCodes);
}
public class ErrorProvider {
public ErrorInfo BuildErrorMessage(string errorCodes) {
return new ErrorInfo(){ErrorCodes = errorCodes};
}
}
public class Class1 {
private readonly IRepository _repository;
private readonly IErrorProvider _errorProvider;
public Class1(IRepository repository, IErrorProvider errorProvider) {
_repository = repository;
_errorProvider = errorProvider;
}
public List<ErrorInfo> GetErrorList(int id) {
var errorList = new List<ErrorInfo>();
string paramName = _repository.GetParameter(id);
if (string.IsNullOrEmpty(paramName)) {
string errorCodes = string.Format("{0}, {1}", 200, 201);
var error = _errorProvider.BuildErrorMessage(errorCodes);
errorList.Add(error);
}
return errorList;
}
}
單元測試
在測試通過下方,我們檢查被測系統內是否使用了正確的錯誤代碼。
[TestMethod]
public void GetErrorList_WhenParameterIsEmpty_ReturnsExpectedErrorCodes2() {
//Arrange
var stubRepo = new Mock<IRepository>();
stubRepo.Setup(x => x.GetParameter(It.IsAny<int>())).Returns(string.Empty);
var stubErrorMock = new Mock<IErrorProvider>();
const int id = 5;
var sut = new Class1(stubRepo.Object, stubErrorMock.Object);
//Act
var result = sut.GetErrorList(id);
//Verify
string verifiableErrorCodes = "200, 201";
stubErrorMock.Verify(x => x.BuildErrorMessage(verifiableErrorCodes));
}
但是我更喜歡測試最終結果。 例如,我要針對生產代碼中使用的錯誤代碼進行斷言。 低於測試失敗,但我想知道您對如何針對被測系統中使用的errorCode斷言的想法。
[TestMethod]
public void GetErrorList_WhenParameterIsEmpty_ReturnsExpectedErrorCodes1() {
//Arrange
var stubRepo = new Mock<IRepository>();
stubRepo.Setup(x => x.GetParameter(It.IsAny<int>())).Returns(string.Empty);
string expectedErrorCodes = "200, 201";
var stubErrorRepo = new Mock<IErrorProvider>();
stubErrorRepo.Setup(e => e.BuildErrorMessage(It.IsAny<string>()));
const int id = 5;
var sut = new Class1(stubRepo.Object, stubErrorRepo.Object);
//Act
var result = sut.GetErrorList(id);
//Assert
Assert.AreEqual(expectedErrorCodes, result.Single().ErrorCodes);
}
測試此系統中已使用的錯誤代碼的正確方法是什么?
我建議僅模擬IRepository
並使用真實的IErrorProvider
。 然后,您可以調用GetErrorList(id)
並檢查結果。
沒有真正正確或錯誤的答案,我們決定使用Assert測試來測試最終結果。
我采用了TDD方法,並如下重新進行了實施/分析。
// AssertTest
[TestMethod]
public void GetErrorList_WhenParameterIsEmpty_ReturnsExpectedErrorCodes1()
{
//Arrange
const string expectedErrorCodes = "200, 201";
var stubErrorRepo = new Mock<IErrorProvider>();
stubErrorRepo.Setup(e => e.BuildErrorMessage(expectedErrorCodes)).Returns(new ErrorInfo() { ErrorCodes = expectedErrorCodes });
var sut = new Class1(stubErrorRepo.Object);
//Act
var result = sut.GetErrorList();
//Assert
Assert.AreEqual(expectedErrorCodes, result.Single().ErrorCodes);
}
// SUT
public IEnumerable<ErrorInfo> GetErrorList(int id)
{
yield return new ErrorInfo();
}
如您所料,測試將失敗。
現在,如果編寫足夠的生產代碼以使此測試通過。
public IEnumerable<ErrorInfo> GetErrorList()
{
yield return _errorProvider.BuildErrorMessage("200, 201");
}
上述SUT的VerifyTest仍然會失敗。
//驗證測試
[TestMethod]
public void GetErrorList_WhenParameterIsEmpty_ReturnsExpectedErrorCodes2()
{
//Arrange
var stubErrorMock = new Mock<IErrorProvider>();
var sut = new Class1(stubErrorMock.Object);
//Act
sut.GetErrorList();
//Verify
string verifiableErrorCodes = "200, 201";
stubErrorMock.Verify(x => x.BuildErrorMessage(verifiableErrorCodes));
}
但是,如果我希望此測試通過,則可以編寫以下生產代碼,如下所示
public IEnumerable<ErrorInfo> GetErrorList()
{
_errorProvider.BuildErrorMessage("200, 201");
return null;
}
現在,VerifyTest通過了,但是AssertTest失敗了。
兩種測試均以其自己的方式有效。 但是,它們測試了不同的語義。 AssertTest測試最終結果是否包含正確的錯誤代碼。 驗證測試可確保使用正確的錯誤代碼調用該方法。 重要的是要注意,Assert測試的最終值基於Moq框架提供的設置方法“ match”。 換句話說,設置指示最終結果是什么。 如果安裝程序配置錯誤或生產代碼使用與安裝程序配置不匹配的錯誤代碼,則AssertTest將失敗。
最好使用AssertTest來測試最終結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.