Sunday, November 27, 2016

Simple Mocking in F# with Object Expressions (I Like This)

Last time I talked about how I had some mixed feelings about testing C# code using FsUnit. I took the last example a step further and added mocking to the FsUnit test. I really like how easy F# makes it to do simple mocking.

Here's a reminder of the test comparison from last time:

FsUnit testing GetSunset

NUnit testing GetSunset

I had some mixed feelings about this (and I'm still working on them a bit). But I decided to take this a step further and add mocking.

Mocking with C# Code
The code above uses hard-coded data in the production file. The next step is to add an actual service call. But, of course, this messes with the tests.

We don't want to have a service call in our tests, so in the code, we add a property to our class so we can do some property injection. But then we need to create a mock of the object.

Here's the interface we need to mock:


And here's a test in NUnit that uses Moq to mock up the interface:

NUnit with Mock Interface

I've used Moq quite a bit in the past, and I've found it to have the features that I've need in my code.

With that said, the setup for Moq takes a bit of getting used to. But what the second line of this test is saying is "If someone calls the 'GetServiceData' method on this object (no matter what parameter), please return them the 'goodResult' object." The "goodResult" object is the JSON string with our test data.

Then a bit further down, we assign the "serviceMock.Object" to the property on our class. We have to use "Object" because this is how we pull the "ISolarService" object out of our "Mock<ISolarService" object.

This is code that I'm used to seeing. But I found it can be a bit better in F#.

Simple Mocking with F#
First, I started to look at Foq (which is an F# version of Moq). But with a little more searching, I found that I didn't even need to use a mocking framework for the simple call that I needed here.

Here's the same test in F#:

FsUnit with Mock Interface

Take a look at the "mock" item at the beginning of the function. This is an Object Expression. By using this, we have an object that behaves like the mock we created above. If someone calls the "GetServiceData" member on the object (with any parameter (as denoted by the '_' that we don't use later)), we want to return "goodData", our JSON string.

Then a few lines down, we assign the mock to the "Service" property. (And we don't have to use the "Object" property like we did with Moq.)

One other thing that I did to this code that cleans it up a bit: I removed the "new" keywords before all of the constructors. This is optional in the F# world, and it makes things a bit better to read.

Wrap Up
I'm still working on readability. This is a key attribute of unit tests. I really like the Object Expression syntax that allows us to create simple mocks very easily. This is more readable than using Moq in C#.

So I'll keep working through this. If you have any suggestions, feel free to let me know. I'm always looking for tips from folks who have more experience with this than I do.

Happy Coding!

2 comments:

  1. For small interfaces, object expressions are great. For everything else, there's Foq (at present the NuGet for the latest version is entitled Foq2)

    http://www.trelford.com/blog/post/FoqItEasy.aspx
    http://trelford.com/blog/post/Foq.aspx

    ReplyDelete
    Replies
    1. Thank you, Ruben. I took a quick look at Foq for this example (I've used Moq quite a bit in my C# code). Most of the mocking that I've needed has been quite simple, and I was happy to see how easy an object expression could make it. I'm still experimenting at this point (I've also done a simple "Verify" with an object expression; I'll show that code in a future article). I will be taking a closer look at Foq as well. It looks like it makes complex mocking much easier (plus, Phillip is an awesome person).

      Thank you for taking the time to share this. Sharing is how we all get better.

      Delete