Генерация случайного правила для теста на основе свойств
Я использую Triq ( erlang quickcheck), и у меня возникают проблемы при создании наборахороших правил для моей программы.
То, что я хочу генерировать, это вещи, которые выглядят так:
A -> B
где я хотел бы предоставить A
и размерB
с последним, не имеющим дубликатов.
Например, если я скажу, сгенерируйте мне правила с LHS [a]
и RHS размера 4 (т.е.A = [a]
а такжеsize(B) = 4
) Я хотел бы получить что-то вроде этого:
{rule, [a], [1,2,4,5]}
{rule, [a], [a,d,c,e]}
{rule, [a], [q,d,3,4]}
Обратите внимание, я не хочу дубликатов в B (это часть, с которой у меня проблемы). Кроме того, на самом деле не имеет значения, из чего состоит B - это может быть что угодно, лишь бы оно было разным и без дубликатов.
Моя спецификация слишком грязная, чтобы показывать ее здесь, поэтому я бы предпочел не делать этого.
1 ответ
Я не знаком с Triq, но в PropEr и Quviq's Qickcheck вы можете использовать ?SUCHTHAT
условия, которые фильтруют "плохие" экземпляры.
Если сгенерированный экземпляр не удовлетворяет ограничению?SUCHTHAT, он отбрасывается и не считается действительным тестом. Вы можете использовать этот механизм для генерации списков указанного размера (то есть того, что PropEr называет "векторами"), а затем отбрасывать те, которые имеют дубликаты, но я думаю, что тогда будет отброшено слишком много экземпляров (см. Также ссылку).
Обычно более эффективно возиться с генератором, чтобы все экземпляры были действительными, в вашем случае, например, сгенерировав (3) X-кратное количество элементов, удалив дубликаты и сохранив столько, сколько вам нужно. Это все еще может потерпеть неудачу, и это потерпит неудачу, поэтому вы должны остерегаться этого.
Вот генератор для вашего случая в PropEr вместе с фиктивным свойством:
-module(dummy).
-export([rule_prop/0]).
-include_lib("proper/include/proper.hrl").
-define(X, 5).
rule_prop() ->
?FORALL(_, rule_gen(integer(), 4, integer()), true).
rule_gen(A, SizeB, TypeB) ->
?LET(
EnoughB,
?SUCHTHAT(
NoDupB,
?LET(
ManyB,
vector(?X * SizeB, TypeB),
no_dups(ManyB)
),
length(NoDupB) >= SizeB
),
begin
B = lists:sublist(EnoughB, SizeB),
{rule, A, B}
end).
no_dups([]) ->
[];
no_dups([A|B]) ->
[A | no_dups([X || X <- B, X =/= A])].