Search code examples
jdbcmicronautmicronaut-data

Micronaut-Data JDBC - Multiple Dialects for Test and Production


The Mirconaut docs on JDBC repositories clearly tells us we have to create a test repository to test against another dialect. I think this will be manageable (e.g. Postgres for production and H2 for test).

The problem is I have to repeat my methods (e.g. find()) in the test repository. I have a book repository and a test repository:

@JdbcRepository(dialect = Dialect.POSTGRES)
interface BookRepository extends CrudRepository<Book, Long> {
  Optional<Book> find(String title);
}

@JdbcRepository(dialect = Dialect.H2)
@Replaces(bean = BookRepository)
@Requires(env = ["test"])
interface TestBookRepository extends BookRepository {
  // Optional<Book> find(String title);
  // Required to make the find() method appear in the TestBookRepository
}

To make the find() method available in the TestBookRepository, I had to repeat the method (see commented line above).

Is there a better way to avoid repeating myself? The methods from the CrudRepository interface are available in the TestBookRepository without problems. Why is the find() method not treated the same?

BTW, I don't want to mock the test repository. I want to test the repository 'logic' injected by Micronaut-Data against an SQL database.

This is for Micronaut Data 1.0.0.M5, using Groovy for the source.


Solution

  • To make the find() method available in the TestBookRepository, I had to repeat the method (see commented line above).

    I cannot reproduce that behavior. In order for that to be the case I think the java compiler would need to have a bug in it that caused that.

    See the project at https://github.com/jeffbrown/mikehoustonrepository.

    https://github.com/jeffbrown/mikehoustonrepository/blob/82b8af568042c762a86cef9965e52fdc61053421/src/main/java/mikehoustonrepository/BookRepository.java

    // src/main/java/mikehoustonrepository/BookRepository.java
    package mikehoustonrepository;
    
    import io.micronaut.data.jdbc.annotation.JdbcRepository;
    import io.micronaut.data.model.query.builder.sql.Dialect;
    import io.micronaut.data.repository.CrudRepository;
    
    import java.util.Optional;
    
    @JdbcRepository(dialect = Dialect.POSTGRES)
    public interface BookRepository extends CrudRepository<Book, Long> {
        Optional<Book> find(String title);
    }
    

    https://github.com/jeffbrown/mikehoustonrepository/blob/82b8af568042c762a86cef9965e52fdc61053421/src/test/java/mikehoustonrepository/TestBookRepository.java

    // src/test/java/mikehoustonrepository/TestBookRepository.java
    package mikehoustonrepository;
    
    import io.micronaut.context.annotation.Replaces;
    import io.micronaut.data.jdbc.annotation.JdbcRepository;
    import io.micronaut.data.model.query.builder.sql.Dialect;
    
    @JdbcRepository(dialect = Dialect.H2)
    @Replaces(BookRepository.class)
    public interface TestBookRepository extends BookRepository{}
    

    https://github.com/jeffbrown/mikehoustonrepository/blob/82b8af568042c762a86cef9965e52fdc61053421/src/main/java/mikehoustonrepository/BookController.java

    package mikehoustonrepository;
    
    import io.micronaut.http.annotation.Controller;
    import io.micronaut.http.annotation.Get;
    import io.micronaut.http.annotation.Post;
    
    import java.util.Optional;
    
    @Controller("/books")
    public class BookController {
    
        private final BookRepository bookRepository;
    
        public BookController(BookRepository bookRepository) {
            this.bookRepository = bookRepository;
        }
    
        @Get("/")
        public Iterable<Book> index() {
            return bookRepository.findAll();
        }
    
        @Post("/{title}/{author}")
        public Book create(String title, String author) {
            return bookRepository.save(new Book(title, author));
        }
    
        @Get("/find/{title}")
        public Optional<Book> findByTitle(String title) {
            return bookRepository.find(title);
        }
    }
    

    https://github.com/jeffbrown/mikehoustonrepository/blob/82b8af568042c762a86cef9965e52fdc61053421/src/test/java/mikehoustonrepository/BookControllerTest.java

    package mikehoustonrepository;
    
    import io.micronaut.http.annotation.Get;
    import io.micronaut.http.annotation.Post;
    import io.micronaut.http.client.annotation.Client;
    import io.micronaut.test.annotation.MicronautTest;
    import org.junit.jupiter.api.Test;
    
    import javax.inject.Inject;
    import java.util.List;
    import java.util.Optional;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    @MicronautTest
    public class BookControllerTest {
    
        @Inject
        BookClient bookClient;
    
        @Test
        public void testFind() throws Exception {
            Optional<Book> book = bookClient.find("The Nature Of Necessity");
            assertFalse(book.isPresent());
    
            bookClient.create("The Nature Of Necessity", "Alvin Plantinga");
    
            book = bookClient.find("The Nature Of Necessity");
            assertTrue(book.isPresent());
        }
    }
    
    @Client(value="/", path = "/books")
    interface BookClient {
        @Post("/{title}/{author}")
        Book create(String title, String author);
    
        @Get("/")
        List<Book> list();
    
        @Get("/find/{title}")
        Optional<Book> find(String title);
    }
    

    That test passes.

    You can see that a different repository is being used for test (TestBookRepository) that is used for other environments (BookRepository).

    I hope that helps.