Alex 75
Alex 75

Reputation: 3236

How to implement a clean base test class with common Assert methods (F#)

I'm trying to createa a base test class where I can setup common methods.

type BaseTest() =

    member self.Assert (functionToEvaluate:bool, ?errorMessage:string) =    
        let a = fun () -> defaultArg errorMessage ""    
        match errorMessage with
        | None -> NUnit.Framework.Assert.That(functionToEvaluate)
        | _ -> NUnit.Framework.Assert.That(functionToEvaluate, a )

[<TestFixture>]
type MyTest () =
    inherit BaseTest()

    [<Test>]
    member self.``test something``() =
        let x = 1
        self.Assert_( (x = 2))
        // or 
        self.Assert_( (x = 2), "x value is not 2")
  1. How to make the code "clean" (let a ... is horrible for me)
  2. How to avoid using this/self in the derived class?
  3. How can I write it like self.Assert(x=1) or even better just Assert(x=1) instead of self.Assert((x=1)) ?

What I want tot do (and I can do with C#) is this:

// in base test class
protected void Assert(bool test) => NUnit.Framework.Assert.That(test);
protected void Assert(bool test, string errorMessage) => NUnit.Framework.Assert.That(test, errorMessage);

// in test class
public void TestSomething() {
     var x = 1
     Assert(x==2)
     // or
     Assert(x==2, "x is not 2")
}

Upvotes: 0

Views: 58

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

Your problem is that you're trying to translate the C# program into F# verbatim and expect it to look "nice" without realizing that the initial C# program is already full of C#-specific tricks that exist in order to make it look "nice". One example is the base class. Why is there a base class? Does it represent something? No, it doesn't: it's there for the sole purpose of avoiding a class name when calling these functions - i.e. you write Assert instead of SomeHelper.Assert. This stems out of the fact that in C# you can't have free-standing functions.

But in F# - you can!

let assrt x = NUnit.Framework.Assert.That(x)
let assrtWith x msg = NUnit.Framework.Assert.That(x, msg)

[<TestFixture>]
type SaleRepositoryTest () =

    [<Test>]
    member self.``test something``() =
        let x = 1
        assrt (x=2)
        assrtWith (x=2) "x is not 2"

(Note that you can't use the name assert, because it's a keyword)

Also note that you generally don't need classes. The fact that in C# you can't do anything without them is a giant mistake that grows out of Java design, which was a misunderstanding of OO.

You can have free-standing functions. If I remember correctly, NUnit should be able to discover such tests just fine (though I can't verify right now):

let [<Test>] ``test something``() =
    let x = 1
    assrt (x=2)
    assrtWith (x=2) "x is not 2"

Finally, I strongly recommend that you consider FsUnit. It can bind to NUnit (if you're locked into that) and provides a nice library of F#-idiomatic assertions.

Upvotes: 3

Related Questions