Mystery Guest

xUnit Test Patterns: Refactoring Test Code has an astounding amount of testing knowledge. Here's an example:

You're having trouble understanding the behavior a test is verifying.

This testing anti-pattern is called Obscure Test. A common cause of Obscure Test is Mystery Guest:

The test reader is not able to see the cause and effect between fixture and verification logic because part of it is done outside the Test Method.

The impact is:

Identify the Mystery Guest

In the test code of Rails applications, the Mystery Guest is often one of four smells:

The last two smells have solutions:

The first two smells require more thought.

Replace fixtures with factories

An offensive Mystery Guest is Rails fixtures and Factory Girl is one defense.

Do you have fixture files like this?

dan:
  name: Dan
  role: developer
  location: San Francisco

phil:
  name: Phil
  role: designer
  location: Boston

Is it important in a specific test that the fixtures used are role-based (developer) or location-based (San Francisco)? If the former is true, we should rename the fixtures in order to reveal the intention: users(:developer) and users(:designer).

Since the community has moved to factories, this testing behavior by Rails developers has been less common. What we call "creating objects with factories", others call creating Fresh Fixtures built using Inline Setup.

Each test method creates a test fixture for its own private use.

This meets our goal for the test reader to better see the cause and effect between fixture and verification logic.

Set up only relevant information

Irrelevant Information is another cause of Obscure Test. Again, Factory Girl is helpful. Consider this setup:

context "user account exists with a matching Facebook uid" do
  setup do
    @uid  = 1234567
    @user = create(:user, fb_user_id: @uid)
  end
  ...
end

We explicitly specify only the attribute on user that matters for this test. We use Factory Girl to create only a user with valid data, and we name a @uid variable to express intent for the otherwise Magic Number 1234567.

External resources

Sometimes we need to assert the contents of a file are what we expect. For example, say we've generated the file by dumping some XML from a web service which we'll then stub out during test runs, using the file as a proxy.

context "the job XML from the web service" do
  setup { @xml_job = IO.read("test/fixtures/jobs/1.xml") }

  should "include the recruiter"s email" do
    recruiter_xml = "<recruiter>recruiter@example.com</recruiter>"
    assert_contains @xml_job, recruiter_xml
  end
end

In this case, test/fixtures/jobs/1.xml is called a Prebuilt Fixture.

To truly avoid a Mystery Guest here, the XML could be inline or have the recruiter's email injected somehow.

Writing "good" tests

Debating "good" code is often subjective. Mystery Guest is memory trick to think about how test code will be read and understood by humans. Can the intended behavior of a subset of the system be understood in one glance at the test? Or is there a Mystery Guest clouding our understanding?