Weeknotes 2023 W19: Stub

May 8​–​14, 2023
1300 words

A mostly uneventful week.

Next week’s week­notes will likely be shorter than usual, as I’m on holiday, traveling, and won’t be too focused on writing stuff down. I travel for the in-the-moment experience, not for generating content to share.


A few quick bits:


I’ve attempted to give Siri a try on my iPhone, but I’m really not a fan. Perhaps I’m not using it properly.

In my last interaction with Siri, I said “Hey Siri! Can you — ” before being interrupted by Siri. I instinctively replied with “stop interrupting me!!!” and then Siri showed me a link to a web page about the psychology of interruption.

The whole thing was remarkably passive-aggressive.


I signed up for another acting course. This one is for beginners as well, but there are follow-up courses available, which creates a path forward for me. It think it’ll be quite different from the Chekhov course that I’m already taking, focusing on script analysis and character creation, which are skills I want to obtain.

Getting out of my head and into my body is wonderful. I’ve certainly got the tendency to (over)think everything in life, which isn’t helpful for acting. It’s great to have something regular to do that is so vastly different from what I typically do.


Self-published books are on the rise, and I’m not sure that is a good thing. A handful of the books that I’ve recently bought were self-published, and the quality varies so greatly. All of them have problems — some small, some big:

This is why publishers exist.

Am I being nit-picky about all this? Perhaps a little. But reading a well-designed, carefully-crafted book can be such a joy. The exact same content, when presented in a less-than-great format, can yield a boring or even frustrating experience.

If you’re thinking about self-publishing a book, get in touch with me so I can help you avoid the biggest mistakes. I’m gladly offering you my assistance. But I think my general recommendation, if you care about quality at all, would be to find a publisher and not to self-publish.


At work, the topic of stubbing and mocking has come up again, in particular because one team was about to codify a standard for stubbing/mocking in which as much is stubbed out as possible for pretty much any type of test. I said “nooooo” and told them of my view on stubbing, which is that stubbing is, in my opinion, a last-resort solution only.

I want to illustrate this with an example, which inserts a given Thingy into the database if it does not yet exist:

class InsertThingyIfNeeded
  def initialize(attrs)
    @attrs = attrs
  end

  def call
    return if FindThingy.new(@attrs).call
    InsertThingy.new(@attrs).call
  end
end

class FindThingy
  def initialize(attrs)
    @attrs = attrs
  end

  def call
    # …
  end
end

class InsertThingy
  def initialize(attrs)
    @attrs = attrs
  end

  def call
    # …
  end
end

The code itself isn’t too important. More interesting are the tests.

The tests for FindThingy and InsertThingy are straightforward: they use the database and don’t stub anything. But the story for InsertThingyIfNeeded is different: the standard approach at my employer is to mock any other service-like class, i.e., mock FindThingy and InsertThingy. In practice, it looks like this, in pseudocode:

describe InsertThingyIfNeeded do
  let(:find_thingy) { stub }
  let(:insert_thingy) { stub }

  before do
    allow(FindThingy).to receive(:new)
      .and_return(find_thingy)
    allow(InsertThingy).to receive(:new)
      .and_return(insert_thingy)
  end

  example do
    InsertThingyIfNeeded.new(attrs).call
    
    expect(find_thingy).to have_received(:call)
    expect(insert_thingy).to have_received(:call)
  end
end

The last few lines are the ones I want to highlight. These are the lines that verify that find_thingy and insert_thingy both received #call. It’s my belief that such tests aren’t really useful, and more importantly, are quite brittle. If FindThingy or InsertThingy ever change, then the stubs in the test will need to be adjust — but probably won’t — because the old tests will keep on passing, even if the actual method calls would cause them to fail.

The issue here is that the test suite contains only unit tests, and no integration tests. All three classes are tested in isolation, but are never tested together. All the tests could pass and test coverage could be at 100%, but the code could still be broken.

All this leads me to the question: what is the use of stubbing? I personally avoid stubbing if at all possible, and resort to it only if there’s no reasonable alternative. I am generally OK with stubbing HTTP requests (with Webmock) and the filesystem. Stubbing can also be useful to speed up tests, but there then needs to be at least one integration test, where nothing is stubbed. You’ve got to test the full path at least once.


Entertainment:


Links:

You can reply to this weeknotes entry by email. I’d love to hear your thoughts!
If you like what I write, stick your email address below and subscribe. I send out my weeknotes every Sunday morning. Alternatively, you can subscribe to the web feed.