0

So this is basically the same question as this, but my motivation is different. Also I'm using cucumber-jvm not the ruby version.

Basically I want to record an expectation with EasyMock.expect() in each Given step, then after all steps are processed I want to call replay() (this is necessary due to how easymock works - you have to record all expectations first and then start the replay phase explicitly).

Is there any way to do this using EasyMock? Is there some other way to integrate Record-Replay-Verify mocking with cucumber?

Jakub Bochenski
  • 3,113
  • 4
  • 33
  • 61

1 Answers1

0

Try to use JMockIt. It has more functions that you can use and also has the mocking algorithm you want. It is simple to apply.

Example:

package jmockit.tutorial.domain;

import java.math.*;
import java.util.*;
import org.apache.commons.mail.*;
import static jmockit.tutorial.persistence.Database.*;

public final class MyBusinessService
{
   public void doBusinessOperationXyz(EntityX data) throws EmailException
   {
      List<EntityX> items =
(1)      find("select item from EntityX item where item.someProperty = ?1", data.getSomeProperty());

      // Compute or obtain from another service a total value for the new persistent entity:
      BigDecimal total = ...
      data.setTotal(total);

(2)   persist(data);

      sendNotificationEmail(data, items);
   }

   private void sendNotificationEmail(EntityX data, List<EntityX> items) throws EmailException
   {
      Email email = new SimpleEmail();
      email.setSubject("Notification about processing of ...");
(3)   email.addTo(data.getCustomerEmail());

      // Other e-mail parameters, such as the host name of the mail server, have defaults defined
      // through external configuration.

      String message = buildNotificationMessage(items);
      email.setMsg(message);

(4)   email.send();
   }

   private String buildNotificationMessage(List<EntityX> items) { ... }
}

Now Using the Expectations API

First, lets use the JMockit Expectations API.

package jmockit.tutorial.domain;

import org.apache.commons.mail.; import jmockit.tutorial.persistence.;

import org.junit.; import mockit.;

public final class MyBusinessService_ExpectationsAPI_Test
{
   @Mocked(stubOutClassInitialization = true) final Database unused = null;
   @Mocked SimpleEmail email;

   @Test
   public void doBusinessOperationXyz() throws Exception
   {
      final EntityX data = new EntityX(5, "abc", "abc@xpta.net");

      // Recorded strictly, so matching invocations must be replayed in the same order:
      new Expectations() {{
(1)      Database.find(withSubstring("select"), any);
         result = new EntityX(1, "AX5", "someone@somewhere.com");

(2)      Database.persist(data);
      }};

      // Recorded non-strictly, so matching invocations can be replayed in any order:
      new NonStrictExpectations() {{
(4)      email.send(); times = 1; // a non-strict invocation requires a constraint if expected
      }};

      new MyBusinessService().doBusinessOperationXyz(data);
   }

   @Test(expected = EmailException.class)
   public void doBusinessOperationXyzWithInvalidEmailAddress() throws Exception
   {
      new NonStrictExpectations() {{
(3)      email.addTo((String) withNotNull()); result = new EmailException();

         // If the e-mail address is invalid, sending the message should not be attempted:
         email.send(); times = 0;
      }};

      EntityX data = new EntityX(5, "abc", "someone@somewhere.com");
      new MyBusinessService().doBusinessOperationXyz(data);
   }
}

Using the Verifications API

package jmockit.tutorial.domain;

import org.apache.commons.mail.*;
import jmockit.tutorial.persistence.*;

import org.junit.*;
import mockit.*;

public final class MyBusinessService_VerificationsAPI_Test
{
   @Tested MyBusinessService service; // instantiated automatically
   @Mocked(stubOutClassInitialization = true) Database onlyStatics;
   @Capturing Email email; // concrete subclass mocked on demand, when loaded

   final EntityX data = new EntityX(5, "abc", "someone@somewhere.com");

   @Test
   public void doBusinessOperationXyzPersistsData() throws Exception
   {
      // No expectations recorded in this case.

      service.doBusinessOperationXyz(data);

(2)   new Verifications() {{ Database.persist(data); }};
   }

   @Test
   public void doBusinessOperationXyzFindsItemsAndSendsNotificationEmail() throws Exception
   {
      // Invocations that produce a result are recorded, but only those we care about.
      new NonStrictExpectations() {{
(1)      Database.find(withSubstring("select"), (Object[]) null);
         result = new EntityX(1, "AX5", "someone@somewhere.com");
      }};

      service.doBusinessOperationXyz(data);

      new VerificationsInOrder() {{
(3)      email.addTo(data.getCustomerEmail());
(4)      email.send();
      }};
   }
}

I hope this answers your query.

Mayank Agarwal
  • 376
  • 2
  • 9
  • Sorry, but this is not a realistic solution. Plus it would be more useful if you had shown, how does it solve the problem – Jakub Bochenski Jun 06 '14 at 16:31
  • Thanks, that's better. Still I think you missed the important point that this has to work with cucumber. Are you sure that this will work in that case? I'm not sure how Cucumber JUnit runner works vs. how the expectations blocks are collected – Jakub Bochenski Jun 06 '14 at 21:34
  • Haven't had a change to try it out yet, but that was the gist of my question – Jakub Bochenski Jun 10 '14 at 17:09
  • Ok. Let me know if it was worked and you can mark it as useful if you found out to be useful. – Mayank Agarwal Jun 10 '14 at 17:13