私たちはかなり長い間TDDを行ってきましたが、リファクタリングする際にいくつかの懸念に直面しています。SRP (単一責任原則) をできる限り尊重しようとしているため、クラスが共通の責任 (検証、ロギングなど) を処理するために使用する多くの構成を作成しました。非常に簡単な例を見てみましょう:
public class Executioner
{
public ILogger Logger { get; set; }
public void DoSomething()
{
Logger.DoLog("Starting doing something");
Thread.Sleep(1000);
Logger.DoLog("Something was done!");
}
}
public interface ILogger
{
void DoLog(string message);
}
モック フレームワークを使用するため、この状況で行うテストの種類は次のようになります。
[TestClass]
public class ExecutionerTests
{
[TestMethod]
public void Test_DoSomething()
{
var objectUnderTests = new Executioner();
#region Mock setup
var loggerMock = new Mock<ILogger>(MockBehavior.Strict);
loggerMock.Setup(l => l.DoLog("Starting doing something"));
loggerMock.Setup(l => l.DoLog("Something was done!"));
objectUnderTests.Logger = loggerMock.Object;
#endregion
objectUnderTests.DoSomething();
loggerMock.VerifyAll();
}
}
ご覧のとおり、テストは、テストしているメソッドの実装を明確に認識しています。この例が単純すぎることは認めざるを得ませんが、テストに何の価値ももたらさない責任をカバーする構成が時々あります。
この例に複雑さを加えてみましょう
public interface ILogger
{
void DoLog(LoggingMessage message);
}
public interface IMapper
{
TTarget DoMap<TSource, TTarget>(TSource source);
}
public class LoggingMessage
{
public string Message { get; set; }
}
public class Executioner
{
public ILogger Logger { get; set; }
public IMapper Mapper { get; set; }
public void DoSomething()
{
DoLog("Starting doing something");
Thread.Sleep(1000);
DoLog("Something was done!");
}
private void DoLog(string message)
{
var startMessage = Mapper.DoMap<string, LoggingMessage>(message);
Logger.DoLog(startMessage);
}
}
わかりました、これは例です。ロガーの実装内にマッパーのものを含め、インターフェースに DoLog(string message) メソッドを保持しますが、これは私の懸念を示すための例です
対応するテストにより、
[TestClass]
public class ExecutionerTests
{
[TestMethod]
public void Test_DoSomething()
{
var objectUnderTests = new Executioner();
#region Mock setup
var loggerMock = new Mock<ILogger>(MockBehavior.Strict);
var mapperMock = new Mock<IMapper>(MockBehavior.Strict);
var mockedMessage = new LoggingMessage();
mapperMock.Setup(m => m.DoMap<string, LoggingMessage>("Starting doing something")).Returns(mockedMessage);
mapperMock.Setup(m => m.DoMap<string, LoggingMessage>("Something was done!")).Returns(mockedMessage);
loggerMock.Setup(l => l.DoLog(mockedMessage));
objectUnderTests.Logger = loggerMock.Object;
objectUnderTests.Mapper = mapperMock.Object;
#endregion
objectUnderTests.DoSomething();
mapperMock.VerifyAll();
loggerMock.Verify(l => l.DoLog(mockedMessage), Times.Exactly(2));
loggerMock.VerifyAll();
}
}
うわー... 別の方法でエンティティを変換するとしたら、マッパー サービスを使用するメソッドを含むすべてのテストを変更する必要があります。
とにかく、大量のテストを変更する必要があるため、大規模なリファクタリングを行うときは本当に苦労します。
この種の問題について議論したいと思います。何か不足していますか?テストしすぎていませんか?