How does my mock know what value I want?

It is early afternoon. You just started your job at Glamorous Inc. Your buddy this morning talked about unit tests. How they want all code to have unit tests but also have code that was written before they started doing that. And they want you to start by getting some of that code under test.

You are raring to go. But now that you are on your own, uncertainty sets in. You have a fair idea what unit tests are. You just never had the opportunity to write that many of them. And these mocking frameworks. You know their purpose, but never used one.

A piece of code is staring back at you. It’s a pretty straightforward function. All it does is read some values from a file to populate some properties.


    class NiceNewJob
    {
      public NiceNewJob(IReader reader)
      {
        Populate(reader);
      }
      
      public string JobTitle {get; private set;}
      public decimal Salary {get; private set;}
      
      private void Populate(IReader reader)
      {
        JobTitle = reader.ReadString("job_title");
        Salary = reader.ReadDecimal("salary");
      }
    }

You know unit tests should not access any files and luckily this class takes an IFileReader in its constructor. So you should be able to mock out this interface. (You are picking up the lingo nicely.)

Looking at similar classes and their tests, you have come up with the test to verify that JobTitle gets populated correctly from the reader passed into NiceNewJob.


    [TestMethod]
    public void 
    {
      var reader = Mock.Create<IReader>();
      var job = new NiceNewJob(reader);
    
    }

So far so good. Creating a new instance of NiceNewJob should have used reader to read values into its properties. So you should be able to write an Assert on the JobTitle value. Something like.

      Assert.AreEqual(job.JobTitle, /*expected value*/);

Gah!

What do you use for the expected value?!

It should be something predictable. Something that keeps the same value regardless of when, where or how often it is executed. Of course the IReader mock should return that value when NiceNewJob calls for it.

But how? How, for Pete’s sake, would that mock know what value you coded as the expected value?

Hang on to your hat.

Mocking frameworks may seem like magic, but really they are not. They are code just like all other code. And while a mocking framework can save you a lot of (tedious) manual coding of your test doubles, it can’t read your mind. Sorry.

This line


      var reader = Mock.Create<IReader>();

is instructing the mocking framework to create a new instance of some class implementing the IReader interface. A mocking framework will ensure that all methods of the class or interface to be mocked are provided with “empty” default behavior. That means either doing nothing (void methods) or returning the default value for the method’s return type.

What is still missing is the specific behavior that you need for your specific test.

There is no way for any mocking framework to have anything more than “empty” behavior without being told explicitly what to do. So every mocking framework will have some way for you to instruct the mock to do your bidding. Exactly how varies per framework. An example could be


    Mock.Arrange(() => reader.ReadString()).Returns("Wizard");

A line like that instructs the mocking framework to return “Wizard” whenever ReadString is called on reader.

Now you know how to get your mock to supply NiceNewJob with a predictable test value, you can finish writing your test.


    [TestMethod]
    public void 
    {
      var reader = Mock.Create<IReader>();
      Mock.Arrange(() => reader.ReadString()).Returns("Wizard");
      
      var job = new NiceNewJob(reader);
    
      Assert.AreEqual(job.JobTitle, "Wizard");
    }

Still sounds like magic?

Let’s look at this then as if you did not have a mocking framework and you’d have to code your test double, fake, mock, stub, or whatever you may call it, yourself.

It is not that difficult. You would have to define an IReader test double class yourself and provide implementations for all methods that IReader defines. Any methods you don’t need for your test(s), you can leave “empty”: returning only the simplest value possible (null, 0, "", ...);

For example


    class FakeReader : IReader
    {
      public string ReadString(string key)
      {
        return "Wizard";
      }

      public decimal ReadDecimal(string key)
      {
        return 666.42;
      }

      public int ReadInteger(string key)
      {
        return 0;
      }

      public void Reset
      {
      }
    }

Using your hand coded test double, the code of your test would read as


    [TestMethod]
    public void 
    {
      var reader = new FakeReader;
      
      var job = new NiceNewJob(reader);
    
      Assert.AreEqual(job.JobTitle, "Wizard");
    }

That’s it. Enjoy!

Now go out there and give your tests some nice predictable values to work with.



Leave a Reply

Your email address will not be published. Required fields are marked *

*

Show Buttons
Hide Buttons