How to keep method return type 'void' in F#?
Asked Answered
A

3

10

I'm writing unit tests for my F# library using F#, Visual Studio Unit Testing Framework (aka MSTest) and FluentAssertions.

Test method should have return type either void or Task. In C# that's easy:

[TestMethod]
public void TestMethod1()
{
    false.Should().BeFalse();
}

In F# I have the following:

[<TestMethod>]
member this.TestMethod1() =
    false.Should().BeFalse(null)
    |> ignore

Otherwise return type is changed to FluentAssertions.PrimitivesBooleanAssertions so Test Runner doesn't see it.

How to avoid having |> ignore in the end of each test?

Actinozoan answered 12/3, 2014 at 23:11 Comment(0)
G
15

|> ignore is required here, since the signature of TestMethod1 is inferred from "the inside out". Consider that in C#, the return type of a method is required in the method declaration. These are deep differences between the languages.

"Fluent" APIs are a nuisance in F#, since they involve instance methods that both have an effect and return a value, a red-flag in F#. That is, while side-effects are permitted in F#, they are somewhat quarantined, both in the language specification and by convention. It is expected that a method returning unit has an effect, but conversely a method returning a non-unit value is expected to be pure.

Moreover, fluent APIs seek to solve limitations in languages such as C# that F# doesn't have or solves differently. For example, in F#, the pipe operator + immutable data structure transformations is comparable to a fluent API in an imperative language.

Try using a more idiomatic F# unit testing assertion library, such as Unquote (disclaimer, I am the author). It exploits many of the strengths of F# in the same way FluentAssertions tries to make up for the weaknesses of C#.

Gnomon answered 13/3, 2014 at 1:25 Comment(6)
btw why did you use Google Code instead of Github or Codeplex? These two look a better open source code hosting service to me.Actinozoan
@Actinozoan only Google Code supports both Mercurial and Subversion (SvnBridge doesn't count), my distributed and centralized VCSs of choice. Besides that showstopper, I've always preferred Google Code's simple yet powerful user interface. That being said, I am troubled by Google Code's recent discontinuation of binary hosting, and general lack of further development.Gnomon
Have you considered bitbucket.org then? Not so fancy-schmancy like GitHub but supports Hg and works very well in general.Actinozoan
And does Unquote support string assertions like in my question, i.e. ends with?Actinozoan
I haven't looked too deeply into bitbucket.org, but offhand looks like it doesn't support svn (DVCS is great and all, but CVCS still has its strengths, I believe).Gnomon
Oh yes, the beauty of Unquote is that you use regular F# expressions as your assertions: captured via Quotations as ASTs, Unquote is able to decompile and incrementally reduce them for friendly failure messages. So to assert that a string ends with something, you'd just do e.g. test <@ "my string is good".EndsWith("is good") @>Gnomon
T
8

Just add () at the end of your function

This will return unit

Traceetracer answered 13/3, 2014 at 0:48 Comment(1)
Then I'm getting a warning: This expression should have type 'unit', but has type 'AndConstraint<Primitives.PrimitivesBooleanAssertions>'. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name.Actinozoan
P
2

In F#, you could try instead FsUnit

You cannot return void in F#, thanks Gods! When you use |> ignore at the end of a method, the method returns unit. In F#,

'System.Void' can only be used as 'typeof<System.Void>'

Peshitta answered 12/3, 2014 at 23:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.