Tag Archives: RSpec

Java RSpec alternative

I simply adore RSpec in Ruby land ­čÖé It helped me embrace TDD in the best manner possible – by not getting into my way. Doesn’t sound much but it feels great when TDD cycle is so fast and unobtrusive that one simple cannot help running the spec over and over again. I don’t know, for me it feels like “let’s run the specs once again, if nothing else than to see how fast they run”. Compulsive but I can’t help it ­čÖé

Anyway, I’ve been working on some Java projects these couple of weeks and wanted the same TDD comfort zone as I get with RSpec. And a combination of Mockito, JUnit and PowerMock┬áseems to be doing the trick. How about some code?:

public final class Blender {
  // ...
}

public class CreateYummyShake {
  private Blender blender;

  public CreateYummyShake(Blender blender) {
    // ...
    this.blender = blender;
  }

  public Shake with(List fruit) {
    return mix(takeRipe(fruit));
  }

  private Shake mix(List fruit) {
    // mix the fruit using blender
    // put it in glass
    // ...
  }

  protected List takeRipe(List Fruit) {
    new FilterFruit(fruit).takeRipe();
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({Blender.class})
public class CreateYummyShakeTest {
  private Blender blender;

  @Before
  public void setup() {
    fruit = new ArrayList();
    fruit.add(mock(Fruit.class));
    fruit.add(mock(Fruit.class));
    blender = PowerMockito.mock(Blender.class); // mock final class with PowerMockito
    subject = spy(new CreateYummyShake(blender)); // spy the subject of the test, we need this later
  }

  @Test
  public void createsYummyShake() {
    doReturn(ripeFruit).when(subject).takeRipe(anyCollectionOf(Fruit.class)); // intercept call to another use case, no need to test this since it has it's own test
    when(blender.blend(fruit)).thenReturn(...); // use PowerMockito mock as you would use a Mockito one
    assertArrayEquals(ripeFruit.toArray(), subject.with(allFruit).ingredients.toArray());
  }
}

Before I explain this, a quick disclaimer: this code is nowhere near perfect or even nice, but hopefully it server the purpose of exposing some details about the test tools used. Consider yourself warned ­čÖé

Anyway, as you can see, Mockito plays well with collaborators and other use cases in the code. However, it can’t mock final classes (and some other combinations too, but you can look it up if need be). That’s where PowerMock┬ácomes in. It does the job, and as a bonus it lets you use those mock with Mockito as if nothing changed.

Also, subject under test might be using some other collaborator (ripe fruit filter in this case) and have a hard connection to it. Now, usually this would be injectable and easily mocked in test, but for the sake of argument, how does one test this? By extracting access to that collaborator to a protected method and stubbing it’s result. Mockito offers the ability to spy the subject under test. This way, the extracted access method can be mocked and the test is simplified. A separate test for the collaborator should exist of course.

The rest of Mockito DSL and options is pretty nice. It it not as pleasant as RSpec but it comes pretty close. I’ve always liked how RSpec tests read like prose, and this comes pretty close. The only issue I have is with asserts, but that can’t be helped unless JRuby is used, but that’s another story altogether.

Lastly, if you use Maven, you need these dependencies:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-all</artifactId>
  <version>1.9.5</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>1.5</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>1.5</version>
  <scope>test</scope>
</dependency>
Tagged , , , ,

Stubbing Amazon API calls using VCR

When integrating with external services, it is wise to test those interactions. But then again, it soon becomes tedious and slow if you need to repeat tests and wait for those external services responses. So VCR gem comes to the rescue! Much has been written about it so I want go into details, but what put a smile on my face was the solution for the integration test where I needed to test searching Amazon item listings using Vacuum gem. So to test my code I needed to a way to:

  • tell VCR to record the Vacuum gem request and Amazon API response
  • reuse it for subsequent test runs

Two things bothered me:

  • Vacuum uses Excon for HTTP layer
  • Amazon API calls are┬ásigned, making two identical search calls have different URI’s – the difference being e.g. with Timestamp part of it

So how does one hook into these layers for test purposes? Fortunately, VCR comes with solutions for both issues.

There is a hook_into VCR configuration option for Excon. Essentially this means VCR can intercept Vacuum calls, great! Configuration is simple, just add :excon hook in spec helper, like in the gist below.

For signed Amazon API requests, VCR magic was needed ­čÖé As you probably know, VCR saves the request and response to appropriate cassettes. For tests within cassette it tries to match the request from the test to the saved ones by comparing HTTP method and URI, as explained here. I couldn’t use it since Amazon API requests are signed, remember? And the existing matchers were of no help either. But, VCR also allows for custom matchers. So, I created a custom matcher that compares search keywords from request uri and that was it!

Now, when running tests, on first run the VCR records the Amazon API request and response to the configured location (spec/fixtures/vcr_cassettes in my case). Subsequent runs reuse those calls. This is more than OK for development tasks. If one needs to refresh the Amazon API response, just delete the saved cassette(s) and the sequence is repeated. Another choice I had to make was whether to store those response in SCM or not? In the end I decided not to save them. Search action is not destructive or otherwise dangerous so any developer can repeat the process without cost. Mind you, in some other use case, e.g. when billing some action over payment gateway, it would probably be wise to store the response.

Tagged , , , , , ,

Running specs without Rails

For most of the Rails work I do, I prefer to run specs without Rails as much as possible. The core of the system is usually in PORO’s so there is no need to wait for Rails environment to load. The idea is picked up from the web, of curse, but with a little twist. In all the PORO’s I reference the spec_helper_without_rails.rb, with the below configuration. Note that some part were left out, because they are not relevant to this topic, but the important part is that Rails is not referenced at all.

Now, to run those specs, one recommendation is to run it with RSpec tags. What bothered me is that Rails environment is loaded after all, because RSpec seems to load all specs before filtering them out. This resulted in PORO specs being executed / filtered out correctly, but the load time was slow as before. The trick eventually is to run RSpec only for those specs that use the above helper without Rails. And for that I created a shell/bash script that does just that:

Now, the PORO specs are fast again (~3000 per second on my machine) and life is beautiful again too ­čÖé

Tagged , ,