繁体   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