Posts Tagged mocking

What was a Classic Tester Became a Mockist…

Saturday, November 26th, 2011

Today I had an interesting experience which I’d like to share with my friends. No, I didn’t discover my dark side, I knew that before. What I found out is that mocking as a test method comes in handy once you get it.

Why Don’t You Use RSpec?

I’ve never been an RSpec fan. Not that I don’t like the BDD-approach, which I do appreciate, I was always scared about its internal complexity. I happened to stay with MiniTest, and this has nothing – and i mean nothing – to do with the opinion of Mr. Rails.

Now, I don’t say that RSpec sucks and is too complex. This would be bullshit and I might even soon switch to using this powerful framework (just to make my friend Justin happy) but right now, this test framework still is too powerful for me.

1
2
3
4
5
6
7
8
9
10
class StringTest < MiniTest::Spec
  describe "String" do
    before do
      @string = "Be nice."
    end
 
    describe "#to_xml" do
      it "returns a string" do
        assert_kind_of String, @string.to_xml
      end

That’s pure MiniTest code, included in Ruby 1.9 and working out-of-the-box.

Testing with Assertions Is Not A Crime!

What MiniTest::Spec gives me is basically a BDD interace for classical testers. I say classic as I learned that testers not using expectations are called classic. Old school. Yo.

I can use the keyword methods describe and it to phrase my requirements to the object (line 2 and 8). Before and after hooks provide convenient setup and teardown blocks (line 3).

However, I still use assertions rather than matchers as found in RSpec. I could use matchers, though. MiniTest provides these.

  it "returns a string" do
    @string.to_xml.must_be_kind_of String
  end

Wow, this is “better readable” in many people’s opinion. I still prefer assertions. But that’s not the point of this essay. What I was going to talk about is mocking. Right, mocking.

Who needs Mocking?

Now let’s say my #to_xml method accepts an additional parameter to configure the behaviour. We’d have to test that, too.

  it "accepts the uppercase option" do
    assert_equal @string.to_xml(uppercase: true),
      "<STRING>BE NICE.<STRING>"
  end

This could go on forever, and we test all the features that the method provides in numerous test cases – or its – uppercase, lowercase, reverse, whatever.

Until now, I’ve been testing only using state verification. I run the method and test the state of my string instance afterwards using assertions. This is called state verification.

Purposeless, I now decide that my app needs another method. Here’s the implementation.

class String
  def to_exemel(options={})
    log "stupid phonetic alias called"
    to_xml(options)
  end

I told you, it doesn’t make any sense. What I want to point out is, the method #to_exemel delegates its arguments to the #to_xml method, which we already tested thoroughly.

Expect the Unexpected!

Testing the logging makes sense, I already use mocking here, as I mock the #log method. More on that in a minute.

1
2
3
4
5
6
describe "#to_exemel" do
  it "delegates to #to_xml" do
    String.any_instance.expects(:log)
 
    @string.to_exemel
  end

However, testing all the behaviour of #to_xml again doesn’t. Here, I found out that mocking is cool, too.

1
2
3
4
5
6
7
8
describe "#to_exemel" do
  it "delegates to #to_xml" do
    @string.
      expects(:to_xml).
      with(:uppercase => false)
 
    @string.to_exemel(:uppercase => false)
  end

First, we define expectations: In the ongoing test case, the #to_xml method must be called on the @string instance along with the specified options hash (line 3-5).

I then call the actual method which is subject of our test. The method will be run – and the mocking framework internally checks, if the #to_xml method is really invoked the way we want it (line 7). If it doesn’t, the test will fail!

I Never Knew It’s Called Behaviour Verification!

What we do here is behaviour verification – we no longer have an assertion checking the final string state (we could do that additionally) but set up an expectation, which changes the workflow of our test slightly.

  • I saved a lot of lines of test code since I do not assert all of #to_xml’s features in the #to_exemel method, again. This is cool.
  • Nevertheless, after mocking my test case includes a lot of knowledge about internal implementation. The test now’s aware that #to_exemel forwards to #to_xml. Changing this implementation detail within the class will break the expectation tests, although the second method might still work from the public perspective.

It seems to be a matter of careful choice when to use mocking, and when not. I for myself still lack the experience to make smart assumptions here. However, I can call now myself a Mocker according to Martin Fowler’s great post, which you should definitely read if you haven’t, yet!

Mocking frameworks?

I found mocha to be a very simple to use mocking framework integrating seamless into MiniTest. Never peeked at the source, though. RSpec comes with a powerful mocking functionality as well, which most people might know, use and appreciate.

Outsights?

The example was stupid, I hope I still could point out the difference between status verification and behaviour verification in this short post. Let me know what you think about it. Good nite, and Mock’n‘Roll!