Thực hiện một cách tiếp cận thực tế hơn cho câu trả lời của pdr . TDD là tất cả về thiết kế phần mềm hơn là thử nghiệm. Bạn sử dụng các bài kiểm tra đơn vị để xác minh công việc của bạn khi bạn đi cùng.
Vì vậy, ở cấp độ kiểm tra đơn vị, bạn cần thiết kế các đơn vị để chúng có thể được kiểm tra theo cách hoàn toàn xác định. Bạn có thể làm điều này bằng cách lấy bất cứ thứ gì làm cho đơn vị không xác định (chẳng hạn như trình tạo số ngẫu nhiên) và trừu tượng đi. Giả sử chúng ta có một ví dụ ngây thơ về một phương pháp quyết định xem một nước đi có tốt hay không:
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);
Phương pháp này rất khó kiểm tra và điều duy nhất bạn thực sự có thể xác minh trong các bài kiểm tra đơn vị là giới hạn của nó ... nhưng điều đó đòi hỏi rất nhiều cố gắng để đi đến giới hạn. Vì vậy, thay vào đó, hãy trừu tượng hóa phần ngẫu nhiên bằng cách tạo giao diện và lớp cụ thể bao bọc chức năng:
public interface IRandom {
public float random();
}
public class ConcreteRandom implements IRandom {
public float random() {
return Math.random();
}
}
Các Decider
lớp học hiện nay cần phải sử dụng lớp bê tông qua trừu tượng của nó, tức là giao diện. Cách làm này được gọi là tiêm phụ thuộc (ví dụ dưới đây là một ví dụ về tiêm xây dựng, nhưng bạn cũng có thể làm điều này với một setter):
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);
Bạn có thể tự hỏi tại sao "mã phình" này là cần thiết. Vâng, đối với người mới bắt đầu, bây giờ bạn có thể chế giễu hành vi của phần ngẫu nhiên của thuật toán bởi vì Decider
bây giờ có một phụ thuộc tuân theo IRandom
"hợp đồng". Bạn có thể sử dụng khung mô phỏng cho việc này, nhưng ví dụ này đủ đơn giản để tự viết mã:
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;
}
}
Phần tốt nhất là điều này có thể thay thế hoàn toàn việc thực hiện cụ thể "thực tế". Mã trở nên dễ dàng để kiểm tra như thế này:
@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));
}
Hy vọng điều này cung cấp cho bạn ý tưởng về cách thiết kế ứng dụng của bạn để các hoán vị có thể bị ép buộc để bạn có thể kiểm tra tất cả các trường hợp cạnh và không có gì.