heaphach
heaphach

Reputation: 1492

Dropwizard Integrated Testing with Mocks for DB

First: Yes I read this https://dropwizard.github.io/dropwizard/manual/testing.html

I want to do some integration testing and tahts why I have to start the entire application. Now the problem is, that I have some interfaces to the "outside world" like DB or one internal Rest-Client, who speaks with one remote app. I want to mock them with mockito. Normally thats no problem.

Now my question: How can I start entire application with mocked DB and mocked client?

The problem at the moment is, that I get this DB connection and client from my configuration class via getDBClient() ... and I'm not willing to build in some test code in my config, because its production code. So if I start the entire app via DropwizardAppRule, the app tries to connect to database, but in testing enviroment, there is no DB available.

Is there a easy way to say: Start my app but if you call DB or client, then use this XY mock?

What I tried yet: One new class "ExtendedService extends Service extends Application" and one "ExtServiceConfiguration extends ServiceConfiguration", but without any success. But I having trouble if I override some methods in the config class returning the mock. It does not fit all together.

At the moment I read the docs for mockito spy, perhaps this can help, but I'm not sure how to use this in the DW integrated tests. I now try to mock 2 of my configuration class methods to return a DB and client mock. Perhaps someone can help me, how to mock the TestConfiguration in the next example code:

@ClassRule
public static final DropwizardAppRule<TestConfiguration> RULE =
        new DropwizardAppRule<TestConfiguration>(MyApp.class, resourceFilePath("my-app-config.yaml"));

EDIT: @ClassRule public static final DropwizardAppRule RULE = new DropwizardAppRule(.....)

In @BeforeClass I do the following:

ServiceConfiguration oldConfig = RULE.getConfiguration();
ServiceConfiguration spy = Mockito.spy(oldConfig);
//Then DB mocking
IDatabaseLayer dBMock = mock(IDatabaseLayer.class);
Mockito.when(dBMock.isConnected()).thenReturn(true);
... // other mocking functions for DB
//this is important, it say, that the mocked config class should use the mocked DB
Mockito.doReturn(dBMock).when(spy).getDataBaseLayer(); // my configuration class has this method, so mocking config class with last created dbMock
// do other mockings if needed

Thats all I had done to start entire application.

Upvotes: 2

Views: 4828

Answers (3)

Natan
Natan

Reputation: 2858

If you want to mock specific things but still keep the whole flow of dropwizard, then you need to manage your own Application instance and make it possible to inject your dependencies to your Application class. Because DropwizardAppRule doesn't give you that flexibility.

Example: You want to be able to override the dependencies on your application class.

public class MyApplication extends Application {

  private FooManager fooManager;

  // Need to leave an empty constructor for other uses
  public MyApplication(){
  }

  public MyApplication(FooManager fooManager){
    this.fooManager = fooManager;
  }

  @Override
  public void run(Configuration configuration, Environment environment) throws Exception {
    if(fooManager == null){
      fooManager = new FooManagerImpl();
    }
    // stuff
  }
}

Then on your test, you create your own instance (or you can create a rule class by copying and modifying DropwizardAppRule source code. Edit: Looks like you can inherit DropwizardTestSupport class and override public Application<C> newApplication().).

  @Test
  public void test(){
    FooManager fooManager = mock(FooManager.class);
    MyApplication myApplication = new MyApplication(fooManager);
    myApplication.run("server", "config.yml");
  }

Upvotes: 4

Natan
Natan

Reputation: 2858

If you really want to run an integration test, I suggest using a memory or temporary database like h2 or sqlite, if you can, by creating a new yml file with the relevant settings; and use a mocked http service such as Wiremock.

Otherwise stick to ResourceTestRules as th3morg suggests.

Upvotes: 4

th3morg
th3morg

Reputation: 4789

I think that you should be using io.dropwizard.testing.junit.ResourceTestRule instead, which is used for testing Jersey resources (i.e. making calls to your REST API endpoints). The DropwizardAppRule will start the whole application and stop it at the end of your test. That class seems to be intended for end-to-end testing in which you would not do any mocking whatsoever.

Upvotes: 2

Related Questions