私は約12年間コードを作成していますが、今回はすべてTDDに慣れていません。このTDD試行のベストプラクティス
さて、物事は変わりつつありますが、私はすべて自分で学習しているので、皆さんが私を助けてくれることを願っています。
私はVERY SIMPLEの胸部クラスのゲームの例を投稿しています。 プレイヤーは胸をつかんで、取得した現在の時刻を登録します。 この胸にはオープンに少し時間がかかります。UIの理由から、オープンに必要な残り時間を表示する必要があります。 各胸にはタイプがあり、このタイプはデータベースのオープンに要する時間の値にバインドされています。
これは、「テストを行わないだけのことを成し遂げた、速い考え方」です。 ChestsDatabaseとDateManagerは、データベースにバインドされた値と現在のシステム時刻がクラスにラップされたシングルトンであると考えてください。もちろん
public class Chest {
private readonly int _type;
private readonly float _timeObtained;
public Chest(int type, float timeObtained) {
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
// It depends heavily on this concrete Singleton class
public float GetRemainingTime() {
return ChestsDatabase.Instance.GetTimeToOpen(_type) - GetPassedTime();
}
// It depends heavily on this concrete Singleton class
private float GetPassedTime() {
return DateManager.Instance.GetCurrentTime() - _timeObtained;
}
}
、私は依存性注入の方法でそれを作ったとシングルトンを取り除くことができた:私は、同じロジックを表現するためのインターフェースを使用する場合
public class Chest {
private readonly ChestsDatabase _chestsDatabase;
private readonly DateManager _dateManager;
private readonly int _type;
private readonly float _timeObtained;
public Chest(ChestsDatabase chestsDatabase, DateManager dateManager, int type, float timeObtained) {
_chestsDatabase = chestsDatabase;
_dateManager = dateManager;
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
public float GetRemainingTime() {
return _chestsDatabase.GetTimeToOpen(_type) - GetPassedTime();
}
private float GetPassedTime() {
return _dateManager.GetCurrentTime() - _timeObtained;
}
}
何?これははるかに "TDDフレンドリー"になるでしょうか? (私が最初にテストを行ったと仮定して)
public class Chest {
private readonly IChestsDatabase _chestsDatabase;
private readonly IDateManager _dateManager;
private readonly int _type;
private readonly float _timeObtained;
public Chest(IChestsDatabase chestsDatabase, IDateManager dateManager, int type, float timeObtained) {
_chestsDatabase = chestsDatabase;
_dateManager = dateManager;
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
public float GetRemainingTime() {
return _chestsDatabase.GetTimeToOpen(_type) - GetPassedTime();
}
private float GetPassedTime() {
return _dateManager.GetCurrentTime() - _timeObtained;
}
}
しかし、どうしてそんなことをテストするのですか? このようになりますか?
[Test]
public void SomeTimeHavePassedAndReturnsRightValue()
{
var mockDatabase = new MockChestDatabase();
mockDatabase.ForType(0, 5); // if Type is 0, then takes 5 seconds to open
var mockManager = new MockDateManager();
var chest = new Chest(mockDatabase, mockManager, 0, 6); // Got a type 0 chest at second 6
mockManager.SetCurrentTime(8); // Now it is second 8
Assert.AreEqual(3, chest.GetRemainingTime()); // Got the chest at second 6, now it is second 8, so it passed 2 seconds. We need 5 seconds to open this chest, so the remainingTime is 3
}
これは論理的に正しいですか?何か不足していますか?これは非常に大きく、畳み込まれているので、間違っているようです。私はこれらのテストの目的のために〜2つの余分なクラスを作成しなければなりませんでした。
はのはモックフレームワークを見てみましょう:
[Test]
public void SomeTimeHavePassedAndReturnsRightValue()
{
var mockDatabase = Substitute.For<IChestsDatabase>();
mockDatabase.GetTimeToOpen(0).Returns(5);
var mockManager = Substitute.For<IDateManager>();
var chest = new Chest(mockDatabase, mockManager, 0, 6);
mockManager.GetCurrentTime().Returns(8);
Assert.AreEqual(3, chest.GetRemainingTime());
}
私はフレームワークを持つ2つのクラスを処分したが、それでも、私は間違って何かがあると感じています。私の論理にはもっと単純な方法がありますか?この単一のケースでは、模擬フレームワークや実装クラスを使用しますか?
皆さんはテストを一掃してもらえませんか、私のソリューションのいずれかを主張しますか?またはこのソリューションをより良くする方法は?
私のTDD旅で私を助けてくれることを願っています。ありがとう。