簡體   English   中英

單元測試針對最終結果斷言或驗證是否使用Moq調用了參數

[英]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方法,並如下重新進行了實施/分析。

  • 從失敗的測試開始(為簡化代碼,我從測試和sut中都刪除了存儲庫)

// 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM