Использование NUnit с общими размеченными объединениями

Я пытаюсь использовать FsUnit (под капотом он использует NUnit) для проверки моего кода F #, но у него возникают проблемы с обработкой общих размеченных объединений. Я понимаю, почему это происходит, но я пытаюсь найти способ писать тесты без аннотирования ожидаемых значений. Любой совет? Может быть, для этого лучше подходят фреймворки?

type OptionWithReason<'a> =
  | Some of 'a
  | None of string

let reason = "division by 0 is not yet supported"
let safeDivide x y = 
    if y = 0 then 
        None reason
    else
        Some(x/y)

let result = safeDivide 1 0

let expected = None reason
let expectedExplicit: int OptionWithReason = None reason

let test1 = result = expected //true
let test2 = result = expectedExplicit //true

NUnit.Framework.Assert.AreEqual(expectedExplicit,result) //pass
NUnit.Framework.Assert.AreEqual(expected,result) //fail :(

person DevNewb    schedule 14.12.2017    source источник


Ответы (3)


Часть проблемы в вашем коде заключается в том, что Assert.AreEqual принимает два параметра в качестве obj, и поэтому компилятор не знает, что типы должны быть одинаковыми - если он знает это, он сделает вывод, что expected имеет тип int OptionWithReason (чтобы соответствовать result).

Простой способ исправить это — определить вспомогательную функцию для areEqual, которая принимает параметры того же типа:

let areEqual (first:'T) (second:'T) = 
  NUnit.Framework.Assert.AreEqual(first, second)

Теперь вы можете написать свое утверждение как:

areEqual expected result

Компилятор сделает вывод, что типы expected и result одинаковы, и он должен работать.

person Tomas Petricek    schedule 14.12.2017
comment
Хорошо, ваше решение на самом деле намного проще, чем то, что я нашел (переход на Unquote). Я собираюсь отметить его как принятый, хотя я буду придерживаться Unquote, так как это крутая библиотека для использования в моем игрушечном проекте :) - person DevNewb; 15.12.2017

Думаю, я нашел это. Unquote вроде работает. Я использовал его с xUnit только потому, что его было проще настроить с основными библиотеками dotnet. Мне нужно было только импортировать библиотеки и изменить утверждения:

open Xunit
open Swensen.Unquote

[<Fact>]
let testDUComparison () = 
    test <@ expected = result @>

[<Fact>]
let testDUComparisonExplicit () = 
    test <@ expectedExplicit = result @>

Это позволяет избежать проблемы, потому что мы используем равенство F# вместо того, чтобы передавать его в библиотеку C# как OptionWithReason<object>

person DevNewb    schedule 14.12.2017

let expected = None reason

Здесь компилятор не может знать тип универсального параметра 'a, поэтому при использовании используйте его в

NUnit.Framework.Assert.AreEqual(expected,result)

Это станет эквивалентом экземпляра OptionWithReason<object>, который будет отличаться от любого экземпляра OptionWithReason<int>, как в случае result.

Что касается тестовой среды, вы можете попробовать Expecto. Но все же, я думаю, это создаст ту же проблему

person xuanduc987    schedule 14.12.2017
comment
Как я уже сказал: я понимаю, почему это происходит, я ищу лучшее решение, чем аннотировать - person DevNewb; 14.12.2017
comment
Тогда я думаю, что ответ - нет, потому что без аннотирования типа это был бы другой тип. - person xuanduc987; 14.12.2017