2016-09-06 24 views
5

Przeprowadzam niektóre testy właściwości w F # przy użyciu FsCheck. Dlatego chciałbym zagwarantować, że pewne warunki zawsze będą obowiązywać, niezależnie od argumentów wejściowych.Co to jest zwięzła, ogólna metoda testowania właściwości na podstawie wartości nan w F #?

Rozważę zdefiniowanie banalnej funkcji tożsamości dla wartości float.

let floatId (x : float) = x 

I następnie zdefiniować test tej funkcji, które znam powinien zawsze posiadać:

let ``floatId returns input float`` x = floatId x = x 

jest to trywialne testy, jestem po prostu sprawdzając, nazywając moją funkcję tożsamości pływak wraca taka sama jak zmienna wejściowa.

I następnie podłącz tę funkcję w FsCheck:

Check.Quick ``floatId returns input float`` 

Niestety, ten test nie powiedzie własność!

Falsifiable, after 21 tests (0 shrinks) (StdGen (1872424299,296201373)): 
Original: 
nan 

Oczywiście, patrząc wstecz, to było dość oczywiste, to się wydarzy, wiemy, że nan <> nan.

Ze względu na porównanie strukturalne w języku F # może to powodować (nieco) bardziej złożone przypadki testowe z kolekcjami.

Gdybym zaprojektować funkcję podobną do list float: znowu

let listFloatId (lst : float list) = lst 

let ``listFloatId returns input float list`` lst = listFloatId lst = lst 
Falsifiable, after 6 tests (3 shrinks) (StdGen (1874889363,296201373)): 
Original: 
[nan; 2.0; 2.25; 4.940656458e-324] 
Shrunk: 
[nan] 

sam problem!


Oczywiście mogę zaprojektować ten problem tworząc własne funkcje testowania równości, to w porządku dla float wartości, ale staje się coraz bardziej skomplikowane, aby przedłużyć do zbiorów takich jak list ponieważ muszę zacząć używać List.forall2 z mojej funkcji niestandardowych równości i ogólnie specjalizuję mój kod do każdego indywidualnego typu kolekcji.

Czy istnieje ogólny sposób rozwiązania tego problemu w F #?

+1

Prawdopodobnie rozwiązałbym to z nowym operatorem, który zrobił równość biorąc pod uwagę nan –

+0

@JohnPalmer Robię to, aby umieścić jedno możliwe rozwiązanie, które nie wydaje się być dobrze znane na płycie. Zdecydowanie byłbym zainteresowany słuchaniem innych. – TheInnerLight

+0

Ah - nie zdawałem sobie sprawy, że masz już na to odpowiedź - wygląda na to, że ta funkcja jest w zasadzie tym, czego potrzebujesz. –

Odpowiedz

5

Możesz rozwiązać ten problem, używając funkcji LanguagePrimitives.GenericEqualityER. Sprawdza to równość przy użyciu semantyki Relacja równoważności. Ta funkcja faktycznie umieszcza konkretny przykład porównywania list [nan].

przypadki testowe można zdefiniować tak:

let ``ER : floatId returns input float`` x = LanguagePrimitives.GenericEqualityER (floatId x) x 

let ``ER : listFloatId returns input float list`` lst = LanguagePrimitives.GenericEqualityER (listFloatId lst) lst 

Tym razem:

Ok, passed 100 tests. 
Ok, passed 100 tests. 

(pytam, i odpowiadając na to pytanie, ponieważ powyższa nieruchomość została podniesiona w kanał FSharp Software Foundation Slack i pomyślałem, że byłoby użyteczne mieć to rozwiązanie na płycie.Nie mogę znaleźć prawie żadnej wzmianki o tej funkcji online poza dokumentacją na module LanguagePrimitives).