Більш практичний підхід до відповіді pdr . TDD - це все про дизайн програмного забезпечення, а не про тестування. Ви використовуєте одиничні тести, щоб перевірити свою роботу під час роботи.
Отже, на рівні тестування одиниці потрібно сконструювати одиниці, щоб вони могли бути випробувані повністю детерміновано. Це можна зробити, взявши все, що робить одиницю недетермінованою (наприклад, генератор випадкових чисел) та абстрагує її. Скажімо, у нас є наївний приклад способу вирішити, чи хороший хід чи ні:
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);
Цей метод дуже важко перевірити, і єдине, що ви дійсно можете перевірити в одиничних тестах, це його межі ... але для цього потрібно багато спроб дістатися до меж. Тож замість цього давайте абстрагуємо рандомізовану частину, створивши інтерфейс та конкретний клас, який охоплює функціональність:
public interface IRandom {
public float random();
}
public class ConcreteRandom implements IRandom {
public float random() {
return Math.random();
}
}
Тепер Decider
класу необхідно використовувати клас конкретного через його абстрагування, тобто інтерфейс. Такий спосіб роботи називається ін'єкцією залежності (приклад нижче - приклад конструкторської інжекції, але це можна зробити і за допомогою сетера):
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);
Ви можете запитати себе, для чого потрібен цей "код". Ну, а для початку ви зараз можете знущатися над поведінкою випадкової частини алгоритму, оскільки Decider
тепер існує залежність, яка відповідає IRandom
s "контракту". Ви можете використовувати для цього глузливі рамки, але цей приклад досить простий, щоб кодувати себе:
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;
}
}
Найкраще, що це може повністю замінити "фактичну" конкретну реалізацію. Код легко перевірити так:
@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));
}
Сподіваємось, це дає вам ідеї щодо того, як розробити додаток, щоб перестановки могли бути примусовими, щоб ви могли протестувати всі крайові випадки та інше.