0

以下は、テストしたいクラス(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);
}

システムで使用されているこのエラーコードをテストする正しい方法は何でしょうか?

4

2 に答える 2

1

のみをモックしてIRepository、実際の を使用することをお勧めしIErrorProviderます。GetErrorList(id)その後、呼び出して結果を確認できます。

于 2012-11-08T11:31:07.597 に答える
0

正しい答えも間違った答えもありません。最終結果をテストするため、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 は引き続き失敗します。

//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 を使用することをお勧めします。

于 2012-11-20T11:56:42.697 に答える