Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing a Play controller using mocks

The title pretty much says it all. I would like to set up a traditional JUnit test to mock a controller's dependencies and run tests against actions.

I've found that I can achieve my goal like this:

public class AccountsControllerTest {
    private controllers.Accounts accountsController;

    @Test
    public void test() {
        running(fakeApplication(), new Runnable() {
            public void run() {
                accountsController = new controllers.Accounts();
                accountsController.setAccountsWorkflow(mock(workflow.Accounts.class));
            }
        });
    }
}

The obvious problem here is that I'm instantiating my class under test and injecting mock dependencies from the test method itself, when I should be doing that in the setup() method. It seems that the setup() method is useless if I'm going to test my controller in a traditional way.

Of course I can test controllers the way Play recommends, but my application is dependent on an external SOAP web service, so I need unit tests to show that our code is working when their servers are down.

So, what's the best way to unit test a Play controller using mocks while still taking advantage of setup() and teardown() methods?

Edit

I realize I'm assuming some knowledge here, so for those who are unaware, controller instantiation in a unit test must be wrapped in a running() function or Play! will throw a runtime exception saying that no application has been started.

like image 369
Samo Avatar asked Jun 20 '12 18:06

Samo


People also ask

Should unit tests use mocks?

Mocking should only be used as a last resort, even in unit tests. A method is not a unit, and even a class is not a unit. A unit is any logical separation of code that makes sense, regardless of what you call it.

How do you write a unit test for a controller?

Writing a Unit Test for REST Controller First, we need to create Abstract class file used to create web application context by using MockMvc and define the mapToJson() and mapFromJson() methods to convert the Java object into JSON string and convert the JSON string into Java object.

Should you unit test a controller?

If you've writing custom filters, routes, etc, you should unit test them, but not as part of your tests on a particular controller action. They should be tested in isolation.


1 Answers

You could accomplish this using Mockito and Play's FakeApplication and setting the static Http.Context variable.

This way you can write the test like all other JUnit test.

Example:

...
import static play.test.Helpers.status;
import play.test.FakeApplication;
import play.test.Helpers;
import play.mvc.Http;
import play.mvc.Result;
...

@RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {

  public static FakeApplication app;

  @Mock
  private Http.Request request;

  @BeforeClass
  public static void startApp() {
      app = Helpers.fakeApplication();
      Helpers.start(app);

  }

  @Before
  public void setUp() throws Exception {
      Map<String, String> flashData = Collections.emptyMap();
      Http.Context context = new Http.Context(request, flashData, flashData);
      Http.Context.current.set(context);
  }

  @Test
  public void testIndex() {
      final Result result = Application.index();
      assertEquals(play.mvc.Http.Status.OK, status(result));
  }

  @AfterClass
  public static void stopApp() {
      Helpers.stop(app);
  }
like image 90
Zapodot Avatar answered Oct 18 '22 13:10

Zapodot