2016-12-07 1 views
2

У меня есть GenServer, который отвечает за контакт с внешним ресурсом. Результат вызова внешнего ресурса не важен, когда-либо сбои время от времени приемлемы, поэтому использование handle_cast представляется подходящим для других частей кода. У меня есть интерфейсный модуль для этого внешнего ресурса, и я использую один GenServer для доступа к ресурсу. Все идет нормально.Как правильно проверить handle_cast в GenServer?

Но когда я попытался написать тест для этого gen_server, я не мог понять, как тестировать handle_cast. У меня есть функции интерфейса для GenServer, и я пытался их протестировать, но они всегда возвращают :ok, за исключением случаев, когда GenServer не работает. Я не мог проверить это.

Я немного изменил код. Я отвлек код в handle_cast на другую функцию и создал аналогичный обратный вызов handle_call. Тогда я мог легко проверить handle_call, но это было вроде взлома.

Я хотел бы знать, как люди обычно тестируют асинхронный код, вот так. Был ли мой подход правильным или приемлемым? Если нет, что тогда делать?

+0

Что бы вы хотели испытать в 'handle_cast' здесь? Что он смог получить первоначальный контакт с внешним ресурсом? или что это также удалось? Вы действительно хотите связаться с этим внешним ресурсом во время каждого тестового прогона? (Некоторый приблизительный контур кода также будет полезен.) – Dogbert

+0

Нет, я вставляю модуль интерфейса внешнего ресурса в GenServer, поэтому я не хочу фактически связываться с ресурсом (это будет стоить мне денег). Поскольку 'handle_cast' использует некоторые функции интерфейсного модуля, я хочу проверить, что он преуспевает, когда функции возвращают okayish значения. Добавление кода - хорошая идея, я сделаю это сегодня, через несколько часов. – vfsoraki

ответ

3

запрос Литая имеет вид:

Module:handle_cast(Request, State) -> Result 

Types: 
Request = term() 
State = term() 
Result = {noreply,NewState} | 
     {noreply,NewState,Timeout} | 
     {noreply,NewState,hibernate} | 
     {stop,Reason,NewState} 
NewState = term() 
Timeout = int()>=0 | infinity 
Reason = term() 

поэтому довольно легко выполнить модульное тестирование просто назвав его непосредственно (нет необходимости даже запускать сервер), предоставляя Request и State, и заявляя возвращенный Result. Конечно, это может также иметь некоторые побочные эффекты (например, запись в таблицу ets, изменение словаря процесса ...), поэтому вам нужно будет инициализировать эти ресурсы до и проверить эффект после утверждения.

Например:

test_add() -> 
    {noreply,15} = my_counter:handle_cast({add,5},10). 
+0

Кажется правильным решением в моем случае, когда мои функции интерфейса просто действуют как делегаты для функций 'handle_ *'. IDK о других вариантах использования с более сложными функциями интерфейса, но это решит мою проблему. Благодаря! – vfsoraki

2

Трюк заключается в том, чтобы помнить, что процесс GenServer обрабатывает сообщения по очереди последовательно. Это означает, что мы можем убедиться, что процесс получил и обработал сообщение, убедившись, что он обработал сообщение, которое мы отправили позже. Это, в свою очередь, означает, что мы можем изменить любую операцию async на синхронную, выполнив ее с помощью сообщения синхронизации, например, для некоторого вызова.

тест сценарий будет выглядеть следующим образом:

  1. Проблема асинхронного запроса.
  2. Задайте синхронный запрос и дождитесь результата.
  3. Утверждение о влиянии асинхронного запроса.

Если сервер не имеет подходящей функции для синхронизации, вы можете рассмотреть возможность использования :sys.get_state/2 - вызов предназначен для целей отладки, которые должным образом обрабатываются все специальные процессы (в том числе GenServer) и, что, вероятно, самое важное, синхронный. Я бы счел это совершенно правильным, чтобы использовать его для тестирования.

Вы можете прочитать больше о других полезных функций из :sys модуля в GenServer documentation

+0

Хорошие баллы, 1 и 2. Но 3 немного непонятно, как можно было бы проверить некоторые эффекты, которые выполняются в другом процессе? Кажется, нет общего способа для этих случаев, так как каждый случай может иметь или не иметь побочных эффектов. Даже те, кто имеет, могут иметь в основном разные, поэтому утверждения будут разными. – vfsoraki

Смежные вопросы