7

I am trying to unit test a parser that parses a string and returns the corresponding abstract syntax tree (represented as a discriminated union). I figured it would be pretty compact to use Xunit.Extensions' attribute InlineData to stack all test cases on one another:

[<Theory>]
[<InlineData("1 +1 ", Binary(Literal(Number(1.0)), Add, Literal(Number(1.0))))>]
...
let ``parsed string matches the expected result`` () =

However, compiler complains that the second argument is not a literal (compile time constant if I understand it correctly).

Is there a workaround for this? If not, what would be the most sensible way to structure parser result tests while keeping every case as a separate unit test?

nphx
  • 1,426
  • 3
  • 19
  • 30
  • 4
    Don't use attributes. If you want to keep using Xunit, see http://blog.ploeh.dk/2014/03/14/exude/ , otherwise see https://github.com/mausch/Fuchu – Mauricio Scheffer Dec 31 '14 at 20:59
  • @MauricioScheffer I've actually seen that blog post some time ago, thanks for reminding me about it. However, R#'s test runner does not pick up the Exude style tests in F# :/. It works in C#, but the test results behave strangely when one of the "nested" tests fails. – nphx Dec 31 '14 at 21:32
  • Actually, scratch that. It does work in F#, I just defined the test as a value, not as a function. It's a little annoying that R#'s test runner identifies the sequence of test cases as one unit test. Xunit console runner does not have this problem. Feel free to post your suggestion as an answer, I will gladly accept it. – nphx Dec 31 '14 at 22:17
  • 3
    The usual test runners are chock-full of magic and therefore will break all the time. Long-term it's just best to avoid them. – Mauricio Scheffer Jan 01 '15 at 13:41

1 Answers1

1

One possibility is to use xUnit's MemberData attribute. A disadvantage with this approach is that this parameterized test appears in Visual Studio's Test Explorer as one test instead of two separate tests because collections lack xUnit's IXunitSerializable interface and xUnit hasn't added build-in serialization support for that type either. See xunit/xunit/issues/429 for more information.

Here is a minimal working example.

module TestModule

  open Xunit

  type DU = A | B | C

  type TestType () =
    static member TestProperty
      with get() : obj[] list =
        [
          [| A; "a" |]
          [| B; "b" |]
        ]

    [<Theory>]
    [<MemberData("TestProperty")>]            
    member __.TestMethod (a:DU) (b:string) =
      Assert.Equal(A, a)

See also this similar question in which I give a similar answer.

Tyson Williams
  • 1,630
  • 15
  • 35