Дублирующий код между модульным тестом и реализацией
В настоящее время я разрабатываю некоторые низкоуровневые драйверы для встроенной платформы на обычном языке C. Я использую Unity+ Cmock в качестве основы для модульного тестирования
Однако при написании низкоуровневых вещей я часто сталкиваюсь со следующей схемой:
Тестовое задание:
void test_mcp2515_read_register(void)
{
spi_frame_t expected_frame = {{0}};
expected_frame.tx_length = 2;
expected_frame.rx_length = 3;
expected_frame.tx_data[0] = MCP2515_READ_CMD;
expected_frame.tx_data[1] = TEST_ADDR;
expected_frame.callback = callback_test;
spi_transmit_ExpectAndReturn(expected_frame, true);
mcp2515_read_register(TEST_ADDR, callback_test);
}
Реализация:
void mcp2515_read_register(uint8_t addr, spi_callback callback)
{
spi_frame_t frame = {{0}};
frame.tx_length = 2;
frame.rx_length = 3;
frame.tx_data[0] = MCP2515_READ_CMD;
frame.tx_data[1] = addr;
frame.callback = callback;
spi_transmit(frame);
}
Как видите, между тестом и реализацией кода много дублирования.
Это проблема? Я неправильно пишу свои тесты? Или мне вообще не стоит писать тесты для такого низкого уровня?
1 ответ
Эффективность тестового кода обычно не имеет значения. Это зависит от того, что вы пытаетесь протестировать, но дублированный код может указывать на недостаток дизайна.
В вашем случае, возможно, вы могли бы разделить функцию mcp2515_read_register на две части: одну, которая создает структуру, и другую, которая обрабатывает передачу SPI.
Оптимальный дизайн ОО программы, вероятно, будет включать следующие модули:
- SPI драйвер касается только реального общения.
- Драйвер контроллера CAN касается только специфики контроллера.
- Вызывающий абонент ("главный" или любой другой).
- Тестовый код для драйвера контроллера CAN: заменяет основной.
Драйвер SPI объявляет spi_frame_t
как непрозрачный тип, структура, которая касается только данных и связи SPI. Никто за пределами драйвера SPI не знает и не должен знать содержимое этой структуры. Я не знаю, что делает функция обратного вызова, но это не похоже на то, что связано с драйвером SPI. Это скорее похоже на то, что связано с кодом, который вызывает драйвер SPI.
Драйвер контроллера CAN включает в себя драйвер SPI. Он вызывает "конструктор" из драйвера SPI для создания кадра, а затем передает кадр процедурам связи SPI. Драйвер контроллера CAN не имеет тесной связи с функциональностью SPI. Например, не имеет смысла переписывать код вашего контроллера CAN, потому что вы нашли ошибку в SPI. Также вам не нужен контроллер CAN, чтобы иметь возможность использовать SPI, если вы хотите повторно использовать драйвер SPI в другом проекте.
Тестовый случай заменяет вызывающего ("основного") или код контроллера CAN, в зависимости от того, какую часть программы вы пытаетесь протестировать. Он использует те же функции, что и производственный код.