Кодирование интерфейсов дает множество преимуществ, лучшая тестируемость является одним побочным эффектом, связанным с основным преимуществом: отделение объекта от его зависимостей .
СкажемУ меня есть класс A, и в его реализации он использует класс B. Если вы не предоставляете интерфейс для B, то вы тесно связали дизайн A и B вместе (вы не можете рассмотреть A без этогоконкретная реализация B, так как она использует конкретную реализацию).
Если вы пишете интерфейс для B (скажем, IB) и используете его в A вместо непосредственного использования B, то вы развязали дизайн и сделал их независимыми.Теперь A может функционировать независимо от конкретного дополнения B, он знает только интерфейс к нему (IB) и методы, необходимые для его работы.Поэтому, если позже вы решите, что ваша реализация B не была хорошей, или если вы хотите, чтобы A мог работать с двумя различными IB в зависимости от контекста, вы можете заменить B на B2, , который также реализует IB, поэтому вам вообще не нужно изменять A.
Действие по созданию A путем внедрения реализации IB во время выполнения выглядит так:
A myA = new A(new B()); // this could also be new A(new B2()); or anythign else that implements IB
называется Внедрение зависимостей , и это лучший способ для достижения желаемой функции программирования ОО: Инверсия управления (Это не A, который больше контролирует поведение своих зависимостей, это независимый класс -заводская - она контролирует то, что вводится в A).
Для целей тестирования вы можете затем unit-test A, не делая предположений для B (который, очевидно, должен быть проверен отдельно).Таким образом, в ваших тестах вы можете внедрить в A заглушку или поддельную реализацию B, которая поможет вам протестировать поведение, которое вы хотите.
(Извините, никаких реальных примеров кода, так как яJava разработчик и не очень хорошо с синтаксисом C #)