2014-11-20 2 views
4

В настоящее время я разрабатываю некоторые драйверы низкого уровня для встроенной платформы в обычном C. Я использую единицу + 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); 
} 

Как вы можете видеть, что есть много дублирование между кодом между тестом и реализацией.

Это проблема? Я пишу свои тесты неправильно? Или мне не нужно вообще писать тесты на этот материал низкого уровня?

ответ

2

Эффективность тестового кода обычно не имеет значения. Это зависит от того, что вы пытаетесь протестировать, но дублирующий код может указывать на недостаток дизайна.

В вашем случае вы, возможно, разделили функцию mcp2515_read_register на две части: одну, которая создает структуру и другую, которая обрабатывает передачу SPI.

Оптимальный дизайн OO программа, вероятно, включает в себя следующие модули:

  • драйвер SPI касается только с фактической связи.
  • Драйвер контроллера CAN касается только особенностей контроллера.
  • Абонент («главный» или любой другой).
  • Тестовый код для драйвера CAN-контроллера: заменяет основной.

Драйвер SPI объявляет spi_frame_t как непрозрачного типа, в структуры, которая занимается только с данными SPI и связи. Ни один внешний драйвер SPI не знает или не должен знать содержимое этой структуры. Я не знаю, что делает функция обратного вызова, но это не похоже на что-то, связанное с драйвером SPI. Это скорее похоже на что-то, связанное с кодом, который вызывает драйвер SPI.

Драйвер контроллера CAN включает в себя драйвер SPI. Он вызывает «конструктор» из драйвера SPI для создания фрейма, а затем передает кадр на процедуры связи SPI. После этого драйвер контроллера CAN не имеет жесткой связи с функциональностью SPI. Например, нет смысла переписывать ваш код контроллера CAN, потому что вы обнаружили ошибку в SPI. Также вам не нужен контроллер CAN, чтобы иметь возможность использовать SPI, если вы хотите повторно использовать драйвер SPI в другом проекте.

В тестовом случае либо заменяется вызывающий («основной»), либо код контроллера CAN, в зависимости от того, какую часть программы вы пытаетесь протестировать. Он использует те же функции, что и производственный код.

+0

Это почти точно, как создается приложение. Функция обратного вызова необходима, когда выполняется передача (async) SPI. Таким образом, spi_frame_t не зависит от реализации SPI и используется только для указания того, какие данные должны быть переданы. Мой первоначальный вопрос по-прежнему не ответил. Как я могу избежать дублирования кода между тестом и реализацией. Если моя реализация составляет почти 90% копии/вставки из моего теста, какое использование имеет тест. –

+0

@WillemMelching Если кадр SPI не имеет ничего общего с SPI, почему вы назвали его префиксом SPI? Либо вы задали тип запутанного имени, либо ваш код контроллера CAN выполняет то, о чем он не должен относиться. – Lundin

+0

@WillemMelching Во всяком случае, на самом деле не имеет значения, где находится фрейм SPI, потому что вы все еще можете выполнить реализацию с непрозрачным типом и конструктором. Таким образом, создание кадра отделено от передачи, и ваш тестовый код может вызывать конструктор кадра так же, как и функцию производственного кода. Ваше приложение не делает этого, вы используете простые «процедурные структуры программирования», где ваш код приложения тесно связан с типом данных структуры. И поэтому вам нужно повторить код в тестовом примере. – Lundin