Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

f#

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?

like image 384
Matthew MacFarland Avatar asked Oct 27 '15 01:10

Matthew MacFarland


People also ask

Can a 10 year old swear?

It's normal for kids to swear at one time or another. Young kids will often repeat something they've heard. Older kids often want to test their parents' reactions. If your child has started using a few choice words, there are several discipline techniques you can use to curb their use of inappropriate language.

What age is it OK to swear?

It has absolutely no age limit. Ages two and three, you start cursing. Most people begin working around 10 to 14. From 14 to 16, teenagers would most likely swear in front of their parents.


2 Answers

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.

like image 71
Mark Seemann Avatar answered Sep 28 '22 08:09

Mark Seemann


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 @>
like image 34
Matthew MacFarland Avatar answered Sep 28 '22 08:09

Matthew MacFarland