Einen praktischeren Ansatz für die Antwort von pdr wählen . Bei TDD geht es eher um Software-Design als um Testen. Sie verwenden Unit-Tests, um Ihre Arbeit zu überprüfen.
Auf der Ebene der Einheitentests müssen Sie die Einheiten so entwerfen, dass sie vollständig deterministisch getestet werden können. Sie können dies tun, indem Sie alles nehmen, was die Einheit nicht deterministisch macht (wie z. B. einen Zufallszahlengenerator), und das abstrahieren. Nehmen wir an, wir haben ein naives Beispiel für eine Methode, die entscheidet, ob ein Zug gut ist oder nicht:
class Decider {
public boolean decide(float input, float risk) {
float inputRand = Math.random();
if (inputRand > input) {
float riskRand = Math.random();
}
return false;
}
}
// The usage:
Decider d = new Decider();
d.decide(0.1337f, 0.1337f);
Diese Methode ist sehr schwer zu testen und das einzige, was Sie in Unit-Tests wirklich überprüfen können, sind die Grenzen ... aber das erfordert eine Menge Versuche, um an die Grenzen zu gelangen. Lassen Sie uns stattdessen den Randomisierungsteil abstrahieren, indem Sie eine Schnittstelle und eine konkrete Klasse erstellen, die die Funktionalität umschließt:
public interface IRandom {
public float random();
}
public class ConcreteRandom implements IRandom {
public float random() {
return Math.random();
}
}
Die Decider
Klasse muss nun die konkrete Klasse durch ihre Abstraktion, dh das Interface, verwenden. Diese Vorgehensweise wird als Abhängigkeitsinjektion bezeichnet (das folgende Beispiel ist ein Beispiel für die Konstruktorinjektion, aber Sie können dies auch mit einem Setter tun):
class Decider {
IRandom irandom;
public Decider(IRandom irandom) { // constructor injection
this.irandom = irandom;
}
public boolean decide(float input, float risk) {
float inputRand = irandom.random();
if (inputRand > input) {
float riskRand = irandom.random();
}
return false;
}
}
// The usage:
Decider d = new Decider(new ConcreteRandom);
d.decide(0.1337f, 0.1337f);
Sie könnten sich fragen, warum dieser "Code aufblähen" notwendig ist. Nun, für den Anfang können Sie jetzt das Verhalten des zufälligen Teils des Algorithmus verspotten, da der Decider
nun eine Abhängigkeit hat, die dem IRandom
s "Vertrag" folgt . Sie können hierfür ein Mocking-Framework verwenden. Dieses Beispiel ist jedoch einfach genug, um sich selbst zu codieren:
class MockedRandom() implements IRandom {
public List<Float> floats = new ArrayList<Float>();
int pos;
public void addFloat(float f) {
floats.add(f);
}
public float random() {
float out = floats.get(pos);
if (pos != floats.size()) {
pos++;
}
return out;
}
}
Das Beste daran ist, dass dies die "tatsächliche" konkrete Implementierung vollständig ersetzen kann. Der Code wird so einfach zu testen:
@Before void setUp() {
MockedRandom mRandom = new MockedRandom();
Decider decider = new Decider(mRandom);
}
@Test
public void testDecisionWithLowInput_ShouldGiveFalse() {
mRandom.addFloat(0f);
assertFalse(decider.decide(0.1337f, 0.1337f));
}
@Test
public void testDecisionWithHighInputRandButLowRiskRand_ShouldGiveFalse() {
mRandom.addFloat(1f);
mRandom.addFloat(0f);
assertFalse(decider.decide(0.1337f, 0.1337f));
}
@Test
public void testDecisionWithHighInputRandAndHighRiskRand_ShouldGiveTrue() {
mRandom.addFloat(1f);
mRandom.addFloat(1f);
assertTrue(decider.decide(0.1337f, 0.1337f));
}
Hoffe, dies gibt Ihnen Anregungen, wie Sie Ihre Anwendung so gestalten können, dass die Permutationen erzwungen werden, sodass Sie alle Randfälle und so weiter testen können.