0
votes

I am working in a spring-boot app, and I am building my Service and Repository Unit Tests.

I know I can autowire in a standard Repository that Extends the JpaRepository, but what about a standard class with the @Repository annotation that uses @PersistentContext with EntityManager that executes em.createNativeQuery(query, Class).getResultList?

For example, I am running an in memory database and I can autowire a standard JpaRepository and say getOne or getAll and it will execute against my in memory test database and return a result.

But is there a way I can do the same with my SQL repository and have the EntityManger execute the nativeQuery against the test database?

I have not figured this out yet.

2
I don't really understand your question. Do you want to use two SQL databases, one for test purpose, and one for the rest? - DeiAndrei
Or do you already have an in memory DB and just want to execute native queries via enitity manager against it? - DeiAndrei

2 Answers

1
votes

In case you want to execute named queries against an in memory DB with spring boot, you can use @DataJpaTest annotation.

It's pretty simple:

1) Include necessary dependencies in your pom.xml

     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <version>1.5.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
        <version>1.4.194</version>
    </dependency>

2) Annotate your test class:

@RunWith(SpringRunner.class)
@DataJpaTest
@ContextConfiguration(classes = InCaseYouWantConfigurationConfig.class)
public class TestDemo {

3) Autowire your repository or entity manager (for test):

@Autowired
private UserRepository userRepository;

@Autowired
private TestEntityManager entityManager;

4) Let's say you have a entity named user. Create one and use the entity manager to find it:

@Test
public void testNoDb() {

    User user = new User();
    user.setFirstName("First Name");
    user.setLastName("Last name");
    user.setUsername("username");
    user.setPassword("password");
    user.setEmail("[email protected]");
    this.userRepository.save(user);

    Query q = this.entityManager.getEntityManager().createQuery("SELECT u From User u WHERE u.username = :username",
            User.class);
    q.setParameter("username", "username");
    User foundUser = (User) q.getSingleResult();

    Assert.assertEquals("[email protected]", foundUser.getEmail());
}

In this case I use a normal query, but of course you could define a named query and use entityManager.createNamedQuery(...).

1
votes

I feel i did not phrase my question correctly. But I found the answer I needed.

I had a non JPA repository like so:

    @Repository
    public class myRepo {
        @PersistentContext
        private EntityManager em;

        public List findMyObjects(){
           String query = <some complicated SQL query>;
           return this.em.creatNativeQuery(query, "name of a SqlResultsetMapping").getResultList();
        }
    }

Then, inside my unit test I had the following:

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"spring.jpa.hibernate.ddl-auto="})
@DataJpaTest
@Sql(<my sql files>)
public class MyRepoTest{
   @Autowired
   private EntityManager em;

   private myRepo repo;

   @Before
   public void setUp(){
      try{
         Field f1 = repo.getClass().getDeclaredField("em");
         f1.setAccessible(true);
         f1.set(repo, em);
      }
      catch(Exception e){}
   }

   @Test
   public void doMyTest(){
      repo.findMyObjects()
   }
}

This is what finally worked for me. Before making the original post, I had been trying what DeiAndrei mentioned, but the EntityManager object was not getting initialized and nothing would work. Perhaps it is due to the way something else is configured inside this application that I am working inside of, but I hope this helps someone else in the future.