Почему таблица ets переживает ct:init_per_testcase, а не init_per_suite?
У меня есть общий набор тестов, который пытается создать таблицу ets для использования во всех наборах и во всех тестах. Это выглядит так:
-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
all() -> [ets_tests].
init_per_suite(Config) ->
TabId = ets:new(conns, [set]),
ets:insert(TabId, {foo, 2131}),
[{table,TabId} | Config].
end_per_suite(Config) ->
ets:delete(?config(table, Config)).
ets_tests(Config) ->
TabId = ?config(table, Config),
[{foo, 2131}] = ets:lookup(TabId, foo).
ets_tests
Сбой функции со значком. Создание / уничтожение таблицы ets для каждого теста, которая выглядит так:
-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
all() -> [ets_tests].
init_per_testcase(Config) ->
TabId = ets:new(conns, [set]),
ets:insert(TabId, {foo, 2131}),
[{table,TabId} | Config].
end_per_testcase(Config) ->
ets:delete(?config(table, Config)).
ets_tests(Config) ->
TabId = ?config(table, Config),
[{foo, 2131}] = ets:lookup(TabId, foo).
Запустив это, я обнаружил, что это прекрасно работает.
Я смущен этим поведением и не могу определить, почему это произойдет, формируя документы. Вопросы:
- Почему это происходит?
- Как я могу иметь таблицу ets для совместного использования для каждого набора и для каждого теста?
2 ответа
Как уже упоминалось в ответе Паскаля и как обсуждалось только в Руководстве пользователя init_per_testcase
а также end_per_testcase
запустить в том же процессе, что и тестовый набор. Поскольку таблицы ETS связаны с процессом владельца, единственный способ сохранить таблицу ETS в течение всего набора или группы - это передать ее или определить наследующий процесс.
Вы можете легко создать процесс в своем init_per_suite
или же init_per_group
функции, установите его в качестве наследника для таблицы ETS и передать его pid в конфигурации.
Чтобы очистить все, что вам нужно, это убить этот процесс в вашем end_per_suite
или же end_per_group
функции.
-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
all() -> [ets_tests].
ets_owner() ->
receive
stop -> exit(normal);
Any -> ets_owner()
end.
init_per_suite(Config) ->
Pid = spawn(fun ets_owner/0),
TabId = ets:new(conns, [set, protected, {heir, Pid, []}]),
ets:insert(TabId, {foo, 2131}),
[{table,TabId},{table_owner, Pid} | Config].
end_per_suite(Config) ->
?config(table_owner, Config) ! stop.
ets_tests(Config) ->
TabId = ?config(table, Config),
[{foo, 2131}] = ets:lookup(TabId, foo).
Вам также необходимо убедиться, что вы все еще можете получить доступ к своей таблице из процесса тестирования, сделав ее protected
или же public
Таблица ets присоединяется к процессу и уничтожается, как только процесс завершается, если только вы не используете функцию give_away (что, боюсь, в этом случае неосуществимо)
Как и состояние в общем документе tets, каждый тестовый пример, init_per_suite и end_per_suite выполняются в отдельных процессах, поэтому таблица ets уничтожается, как только вы выходите из функции init_per_suite.
fron common_test doc
init_per_suite и end_per_suite будут выполняться в выделенных процессах Erlang, как это делают тестовые примеры. Однако результат этих функций не включается в статистику успешных, неудачных и пропущенных испытаний.
от ETS DOC
Владельцем по умолчанию является процесс, который создал таблицу. Владение таблицей может быть передано при завершении процесса с помощью опции наследника или явным образом путем вызова give_away/3.