2013-09-25 24 views
6

Bir değerin, dahil edilen herhangi bir veriyi de kontrol etmek zorunda kalmadan, ayrımcı bir birliğin özel bir durumu olduğunu kontrol etmek istiyorum. Benim motivasyonum, her bir birim testi ile sadece bir şeyi test etmektir. aşağıdaki gibiFsUnit ile ayrımcılık yapılan bir kuruluşun durumu nasıl kontrol edilir?

örneği (son iki satır derleme hataları verin):

module MyState 

open NUnit.Framework 
open FsUnit 

type MyState = 
    | StateOne of int 
    | StateTwo of int 

let increment state = 
    match state with 
    | StateOne n when n = 10 -> StateTwo 0 
    | StateOne n -> StateOne (n + 1) 
    | StateTwo n -> StateTwo (n + 1) 

[<Test>] 
let ``incrementing StateOne 10 produces a StateTwo``()= 
    let state = StateOne 10 
    (increment state) |> should equal (StateTwo 0)    // works fine 
    (increment state) |> should equal (StateTwo _)    // I would like to write this... 
    (increment state) |> should be instanceOfType<StateTwo> // ...or this 

bu FsUnit yapılabilir mi?

this answer'un farkındayım, ancak her durum için eşleme işlevleri yazmak zorunda kalmamayı tercih ediyorum (gerçek kodumda ikiden çok var).

+0

aslında C# bunu yapmanın oldukça kolay bir yolu yoktur, ancak F # çalışmaz:

open System.Reflection open Microsoft.FSharp.Reflection let (|Pass|Fail|) name (x : obj) = let t = x.GetType() if FSharpType.IsUnion t && t.InvokeMember("Is" + name, BindingFlags.GetProperty, null, x, null) |> unbox then Pass else Fail x 

şimdi çalışıyor olmalı. –

cevap

7

, this answer den isUnionCase işlevi kullanışlı olabilir: Eğer değerleri karşılaştırarak önce bir işlev çağrısı gerektiğinden biraz ayrıntılı var

increment state 
|> isUnionCase <@ StateTwo @> 
|> should equal true 

Not söyledi.

// Copy from https://stackoverflow.com/a/3365084 
let getTag (a:'a) = 
    let (uc,_) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(a, typeof<'a>) 
    uc.Name 

increment state 
|> getTag 
|> should equal "StateTwo" 

bu güvenli tip değildir ve kolayca bir birlik vaka adını yanlış olduğunu dikkat:

benzer fakat daha hafif yaklaşım etiketlerinin karşılaştırılması olabilir. Ben ne yapardım

karşılaştırma amaçlı benzer DU'ları oluşturmaktır: Bu şekilde

type MyStateCase = 
    | StateOneCase 
    | StateTwoCase 

let categorize = function 
    | StateOne _ -> StateOneCase 
    | StateTwo _ -> StateTwoCase 

birden fazla kez kez categorize tanımlamak ve kullanmak.

increment state 
|> categorize 
|> should equal StateTwoCase 
0

Çok şık görünmüyor, ancak devletin bir değerden türü çıkarabilir:

let instanceOfState (state: 'a) = 
    instanceOfType<'a> 

Sonra testinde kullanmak:

(increment state) |> should be (instanceOfState <| StateTwo 88) 

DÜZENLEME

Evet, maalesef her zaman türü MyS tate. Desen eşlemesi veya çirkin yansımanın kaçınılmaz olması gibi görünüyor. Eğer yansımaları kullanarak sakıncası yoksa

+0

Bu işe yaramıyor - ben 'StateOne 88' kullanmama rağmen test geçiyor, bu yüzden değerin bir "StateTwo" olduğunu kontrol etmiyor. –

+1

Bu, "a" türü sadece "MyState" olacağı için çalışmaz. 'InstanceOfState', 'state' parametresiyle ilgili çalışma zamanı türündeki bilgileri kullandığında işe yarayacaktır, ancak bunun anlamı biraz daha farklı çalışması gerekir ... –

1

Görünüşe göre FSUnit, bu kullanım durumunu doğrudan desteklemiyor (ya da edemiyorum).

Bulduğum en iyi şey, aşağıdaki gibi bir TestResult türünü bildirmek ve bu tür sonucu azaltmak için bir eşleme kullanmaktır. İşte

type TestResult = 
| Pass 
| Fail of obj 

azaltarak maç Şimdi

let testResult = 
    match result with 
    | OptionA(_) -> Pass 
    | other -> Fail(other) 

sadece doğru sonucu sağlamak için should equal kullanabilirsiniz olduğunu.Bu çözümün

testResult |> should equal Pass 

faydaları geçersiz sonuç ne Gördüğünüz başarısızlık durumunda güçlü yazarak ama daha önemlisi bulunmaktadır.

0

Eğer Microsoft.FSharp.Core.Choice<_,...,_> türündeki değerlerle sınırlı olsa da, FsUnit zaten belirli bir sendika vakasına karşı bir savı destekliyorsa ne olur?

Bunu, çoklu durum etkin deseniyle kullanalım; bu, sendikal vaka adına karşı kontrol etmek için Yansıma'yı kullanır.

increment state 
|> (|Pass|Fail|) "StateTwo" 
|> should be (choice 1) 
İlgili konular