下面是我要测试的类(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));
}
但我更愿意测试最终结果。例如,我想要对生产代码中使用的错误代码进行断言。下面的测试失败但我想知道你如何对被测系统中使用的errorCodes进行断言的想法。
[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);
}
测试系统中使用的错误代码的正确方法是什么?
答案 0 :(得分:1)
我建议只模拟IRepository
并使用真实IErrorProvider
。然后,您可以拨打GetErrorList(id)
并查看结果。
答案 1 :(得分:0)
没有正确或错误的答案,我们决定使用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仍然会失败。
// 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提供的设置方法“匹配” 框架。换句话说,设置决定了最终结果。 如果设置配置不正确或生产代码使用的错误代码与设置配置不匹配,AssertTest将失败。
最好在测试最终结果时使用AssertTest。