Полагаю, я бы начал с того, что пытался достичь. Так, например, если бы я писал какое-то программное обеспечение для личных финансов, я бы начал с чего-то вроде:
@Test
public void importsTransactionsFromQuicken() {
List transactions = new QuickenImporter().importFrom("filename.qfx");
assertSomeStuffAbout(transactions);
}
Теперь, когда у вас все получится, вы можете выполнить рефакторинг и макет обработки файлов, чтобы избежать некоторого ввода-вывода. Это, вероятно, вытеснит абстракцию для чтения файла.
Затем начните искать другие сценарии. Например, вы даете поврежденные файлы в качестве примера. Ну, что должно произойти в случае повреждения файла?
@Test
public void logsAndRemovesCorruptFiles() {
File cf = new CorruptFile();
Logger ls = new LogSpy();
// Note, this might be the refactored interface for after mocking out I/O
QuickenImporter qi = new QuickenImporter(cf, ls);
List transactions = qi.import();
assertEmptyList(transactions);
assertFileWasDeleted(cf);
assertCorruptLogEntryWasWritten(ls);
}
Вы можете видеть, что я провел некоторый рефакторинг, в том числе инжекцию в конструктор и т. Д., Но тесты действительно пропустили следующий шаг. Что касается функции «Переназначить», то, похоже, она нарушает принцип единой ответственности, поэтому она может принадлежать другому классу, например, классу ImportScheduler
. Если это так, я знаю, что я хочу, чтобы поведение импортера было, когда он не может найти файл, поэтому я проведу еще один тест:
@Test
public void doesntReturnAnyTransactionsWhenFileNotPresent() {
QuickenImporter qi = new QuickenImporter(new NonExistentFile(), NULL_LOGGER);
List transactions = qi.import();
assertEmptyList(transactions);
}
Теперь, чтобы протестировать компонент планирования, я могу написать ImportSchedulerTest
с контрольными примерами для обоих условий (когда у меня есть файл, а когда нет).
Надеюсь, это поможет!