Предположим, я решил написать большое приложение на C или любом другом процедурном языке программирования. У него есть функции с зависимостями вызовов, которые выглядят так:
A
|
+-------------+
| |
B1 B2
| |
+------+ +------+
| | | |
C11 C12 C21 C22
Очевидно, что модульное тестирование функций листьев C11, C12, C21 и C22 очень просто: настроить входы, вызвать функции, утвердить выходы.
Но какова правильная стратегия для обеспечения хорошего юнит-тестирования для B1, B2 и A?
Будет ли Внедрение зависимостей предполагать, что B1
(и B2
также) будет объявлено следующим образом?
// Declare B1 with dependency injection for invoking C11 and C12.
int B1(int input, int (*c11)(int), int(*c12)(int));
Но эта стратегия не кажется масштабируемой, если у меня много уровней вызовов. Только представьте, как будет выглядеть объявление для A
:
int A(int input, int (*b1)(int, int (*)(int), int(*)(int)),
int(*b2)(int, int (*)(int), int(*)(int)),
int (*c11)(int),
int (*c12)(int),
int (*c21)(int),
int (*c22)(int));
Тьфу! Должен быть лучший способ.
Иногда мне кажется, что DI и другие подобные шаблоны, предназначенные для содействия модульности и простоте обслуживания, на самом деле затрудняют ясность кода и усложняют то, что должно быть простым кодированием, в бессмысленные абстракции и запутанные косвенные указания.
Как крупные программные проекты на C, такие как Perl и Ruby, занимаются модульным тестированием?