简体   繁体   中英

How can I use an F# discriminated union type as a TestCase attribute parameter?

I am trying to test that the return result from an F# function matches an expected discriminated union case. I am using NUnit to create the tests and it does not like the discriminated union type as a TestCase parameter. The following test case fails to compile:

[<TestCase("RF000123", Iccm.CallType.Request)>]
let ``callTypeFromCallNumber returns expected call type``
    callNumber callType =
    test <@ Iccm.callTypeFromCallNumber callNumber = callType @>

I expect that this is a limitation of NUnit but I am not completely sure. I have an idea to work around this which I will post as my answer but a more elegant solution will be nice.

How can I use a discriminated union case as a test case attribute parameter?

This isn't a limitation of NUnit, but of the F# language (as well as C# and VB): You can only put constants into attributes, but not objects. Discriminated Unions compile to objects in IL, so you can't put them into attributes.

You can put enums into attributes, though, since they're constants (they're numbers at run-time).

From the example in the OP, it looks like the CallType Discriminated Union has no associated data, so you could consider changing the design to an enum instead:

type CallType =
    | Request = 0
    | Incident = 1
    | ChangeManagement = 2
    | Unknown = 3

You should realise, though, that that makes CallType an enum; it's no longer a Discriminated Union. It should enable you to use the values in attributes, though.

Here is my workaround to the problem. It works just fine although I find it a little bit make shift. I just use strings in place of the types and then pattern match to convert to the actual type in the assertion.

[<TestCase("RF000123", "Request")>]
[<TestCase("IM000123", "Incident")>]
[<TestCase("CM000123", "ChangeManagement")>]
[<TestCase("AR000123", "Unknown")>]
let ``callTypeFromCallNumber returns expected call type``
    callNumber callType =
    test <@ Iccm.callTypeFromCallNumber callNumber = match callType with
                                                     | "Request" -> Iccm.CallType.Request 
                                                     | "Incident" -> Iccm.CallType.Incident
                                                     | "ChangeManagement" -> Iccm.CallType.ChangeManagement
                                                     | _ -> Iccm.CallType.Unknown @>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM