This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office.
SpeedyImgImage decodeImage(List<SpeedyImgDecoder> decoders, byte[] data) { SpeedyImgOptions options = getDefaultConvertOptions(); for (SpeedyImgDecoder decoder : decoders) { SpeedyImgResult decodeResult = decoder.decode(decoder.formatBytes(data)); SpeedyImgImage image = decodeResult.getImage(options); if (validateGoodImage(image)) { return image; } } throw new RuntimeException(); }
Image decodeImage(List<ImageDecoder> decoders, byte[] data) { for (ImageDecoder decoder : decoders) { Image decodedImage = decoder.decode(data); if (validateGoodImage(decodedImage)) { return decodedImage; } } throw new RuntimeException(); }
“Separation of Concerns” in the context of external APIs is also described by Martin Fowler in his blog post, Refactoring code that accesses external services.
// Mock a salary payment library @Mock SalaryProcessor mockSalaryProcessor; @Mock TransactionStrategy mockTransactionStrategy; ... when(mockSalaryProcessor.addStrategy()).thenReturn(mockTransactionStrategy); when(mockSalaryProcessor.paySalary()).thenReturn(TransactionStrategy.SUCCESS); MyPaymentService myPaymentService = new MyPaymentService(mockSalaryProcessor); assertThat(myPaymentService.sendPayment()).isEqualTo(PaymentStatus.SUCCESS);
FakeSalaryProcessor fakeProcessor = new FakeSalaryProcessor(); // Designed for tests MyPaymentService myPaymentService = new MyPaymentService(fakeProcessor); assertThat(myPaymentService.sendPayment()).isEqualTo(PaymentStatus.SUCCESS);
@Mock MySalaryProcessor mockMySalaryProcessor; // Wraps the SalaryProcessor library ... // Mock the wrapper class rather than the library itself when(mockMySalaryProcessor.sendSalary()).thenReturn(PaymentStatus.SUCCESS); MyPaymentService myPaymentService = new MyPaymentService(mockMySalaryProcessor); assertThat(myPaymentService.sendPayment()).isEqualTo(PaymentStatus.SUCCESS);