5

I am trying to unit test my Service classes that looks similiar to this:

   @Service
   public class SomeQueryService {

    private final SomeRepository repository;

    public SomeQueryService(SomeRepository repository) {
        this.repository = repository;
    }

    public void doSomething() {
        // code doing some magic
    }
}

SomeRepository is simple repository interface extending JpaRepository interface.

What I want to do is unit test this service to verify whether it is working properly.

I do not want to use mockito to mock repository behaviour instead, I want to have some in-memory implementation (on list or map) that will imitate database behaviour.

Does Spring provide such fake implementations?

I want to avoid making Stub Implementation of such repository by myself as I will be using such tests in many other places.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Tomasz Bawor
  • 1,447
  • 15
  • 40
  • No it doesn't... Use [Mockito](http://mockito.org) to create a dynamic mock . – M. Deinum Apr 12 '18 at 07:51
  • As I mentioned above, I do not want to use mockito, I want stub implementation to mimic real storage. It is too much effort to mantain test with lot of doReturn().when() mumbo-jumbo... – Tomasz Bawor Apr 12 '18 at 07:56
  • 2
    And what would you gain by including a stub over a mock? You aren't testing anything more then the call... If you have a crappy stub implementation your tests fail not because of your service but your crappy test implementation. If that is what you really want to test test with an in-memory database and let Spring Data JPA create your instance of the repository. – M. Deinum Apr 12 '18 at 07:57
  • I want to focus on testing service logic in my test code, I do not want to have lines of mock configuration and verifying interactions with repositories. When service is saving object I want to have access to it by using repository.findAll(), not verifying whether the object is saved by using veryfy(repo).save(...). – Tomasz Bawor Apr 12 '18 at 08:11
  • It is 1 line of code... Also you shouldn't use the same mechanism for storing and verifying. When calling `save` you now automatically assume that the `findAll` is working correctly. Next to that with Mockito you could (if you want) even create a general purpose stub if you really wanted to. – M. Deinum Apr 12 '18 at 08:15
  • 1
    have a look at http://reallifedeveloper.com/creating-in-memory-versions-of-spring-data-jpa-repositories-for-testing/ (https://github.com/reallifedeveloper/rld-repositories-sample) – Ilya Serbis Sep 15 '18 at 20:53

3 Answers3

1

RealLifeDeveloper has created an MIT-licensed helper-class to do just what you want: implement the repository-interface with a plain-old-java-object that just wraps a Collection, and called it "InMemoryJpaRepository". You will still have to implement some logic yourself1, though it should be easy if your queries are not too complicated.

An article explaining how to do this with example: https://reallifedeveloper.com/creating-in-memory-versions-of-spring-data-jpa-repositories-for-testing/

The repository (which includes other stuff, too) is on github: https://github.com/reallifedeveloper/rld-build-tool

The specific helper-files for creating the inmemory-db are found at https://github.com/reallifedeveloper/rld-build-tools/tree/master/src/main/java/com/reallifedeveloper/tools/test/database/inmemory if you dont want the whole repo.

1 The rule "Don't put logic in tests" exists for a reason and is clearly violated here. However, the well-known and widely-used alternatives mentioned by the other answers, H2-testing and extensive mocking, have their drawbacks too.

julaine
  • 382
  • 3
  • 12
0

The type of testing you are referring to is called "Integration Testing" or "End to end testing" since it tests the whole application or a big chunk of it compared to unit tests that test only one method.

https://www.guru99.com/unit-test-vs-integration-test.html

You should not unit test your repositories, since they are already well tested by the spring team.

Solution:

You can create a test that starts the whole spring container using Spring Boot:

Just create a class in your test folder and annotate it with:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTestClass {

  @Test
     public void test() {
  }

}

You can then configure an embedded database using H2 so that your test does not use the production database, just follow the Spring Boot Database Initialization doc.

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html

PS. You can also create a specific profile using the following annotation on your test class:

@ActiveProfiles("test")

sashok_bg
  • 2,436
  • 1
  • 22
  • 33
  • 2
    Thanks, I am aware of testing using in memory database, I am just looking for a way to make test quick, Setting up spring context takes too long and I want to have instant feedback when I am developing code. Waiting for @SpringBootTest takes just too long for quick and nice feedback loop. – Tomasz Bawor Apr 12 '18 at 08:08
0

No Spring Data does not provide a fake implementation of that interface.

You'll have to create it on your own or use a mocking framework like Mockito.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348