2016-01-15 2 views
1

Мне нужно создать уникальные строки, не связанные null, которые будут использоваться как Dictionary ключей. Я пытался что-то вроде:Создание уникальных строк в FsCheck

public static Gen<NonNull<string>> UniqueStrings() 
{ 
    return from s in Arb.Default.NonNull<string>().Generator 
      select s; 
} 

Затем я использую UniqueString() в:

public static Arb<Foo> Foos() 
{ 
    // Foo's constructor will use the string parameter 
    // as key to an internal Dictionary 
    return (from nonNullString in UniqueStrings() 
      select new Foo(nonNullString.Item)).ToArbitrary(); 
} 

Однако я получаю исключение в свойствах тестирования Foo, поскольку FsCheck иногда порождает ту же строку дважды, в результате чего DuplicateKeyException.

Как я могу сгенерировать уникальные строки, которые нужно передать в конструктор Foo?

+0

Я что-то пропустил? Guid-based 'Guid.NewGuid(). ToString();' будет уникальной строкой. –

ответ

3

Вы не можете заставить генератор FsCheck генерировать уникальные значения, потому что у вас по существу нет доступа к истории ранее сгенерированных значений, и сам FsCheck не гарантирует уникальность.

Что вы можете сделать в этом случае, скажем, произнести список строк, а затем уникальный-ify список, например, с помощью Distinct(). Затем вы также можете сгенерировать список Foo с использованием аналогичного подхода.

Например:

Gen<Foo[]> res = from s in Arb.Default.Set<string>().Generator 
       select s.Select(ss => new Foo(ss)).ToArray(); 

(Примечание Вы не можете использовать с, чтобы получить ss, потому что C# не позволяет смешивать различные методы LINQ, один на Gen, один на IEnumerable)

Предложение, мне интересно, не является ли это дополнительной собственностью, которую вы хотите проверить. Если пользователь Foo должен предоставить ему уникальную строку, как это поддерживается? Что произойдет, если они этого не сделают?

+0

Не возражаете ли вы показать пример того, как уникальный-ify список строк, а затем передать его конструктору 'Foo'? Я попробовал что-то вроде 'from ss в Gen.Default.Set >(). Генератор из s в ss выбирает новые Foo (s)', но я получаю ошибку компиляции, говоря, что для типа 'Gen' нет' SelectMany' ' – rexcfnghk

+0

Я имею в виду' Arb.Default' – rexcfnghk

+0

Конструктор 'Foo' вставляет' string' во внутренний 'Dictionary', поэтому, если параметр' string' не уникален, он будет бросать. ИМХО, это не отличный дизайн, потому что предпосылки настолько неясны, но у меня нет выбора, кроме как придерживаться этой реализации. Все, что я могу сделать, это генерировать больше тестов, надеясь раскрыть его недостатки. – rexcfnghk

0

Вместо генерации строк uniq вы можете добавить простую проверку перед вставкой в ​​словарь.

Обновление: Хорошо. Перемешайте свою строку за поколением. Вы можете прочитать here
это около Integer массива, но вы можете легко настроить его для строки

+0

Я стараюсь не изменять реализацию 'Foo', потому что я просто хочу, чтобы FsCheck не генерировал идентичные« строковые »ключи. Изменение реализации Foo - это как избежать вопроса, а не решать его. – rexcfnghk

2

Для создания уникальных строк, которые можно использовать в Guid генератор, это стандартный способ для создания уникальных строк, даже на несколько компьютеров.

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