1

JDBC 存储库上的 Mircaut 文档清楚地告诉我们,我们必须创建一个测试存储库来测试另一种方言。我认为这将是可管理的(例如用于生产的 Postgres 和用于测试的 H2)。

问题是我必须在测试存储库中重复我的方法(例如 find())。我有一个书库和一个测试库:

@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
}

为了使 TestBookRepository 中的find()方法可用,我不得不重复该方法(参见上面的注释行)。

有没有更好的方法来避免重复自己?CrudRepository接口中的方法在 TestBookRepository 中可用,没有问题。为什么find()方法的处理方式不同?

顺便说一句,我不想​​模拟测试存储库。我想针对 SQL 数据库测试 Micronaut-Data 注入的存储库“逻辑”。

这适用于 Micronaut Data 1.0.0.M5,使用 Groovy 作为源代码。

4

3 回答 3

2

为了使 TestBookRepository 中的 find() 方法可用,我不得不重复该方法(参见上面的注释行)。

我无法重现这种行为。为了做到这一点,我认为java编译器需要有一个导致这种情况的错误。

请参阅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);
}

那个测试通过了。

您可以看到用于测试 ( TestBookRepository) 的不同存储库用于其他环境 ( BookRepository)。

我希望这会有所帮助。

于 2019-12-10T17:37:58.517 回答
1

您可以利用 Micronaut 环境为测试和生产创建不同的环境配置,并在 application-test.yml 中配置相应的数据源配置,并将该数据源用于测试

文档中的 Micronaut 环境

于 2019-12-02T06:18:38.903 回答
1

经过更多的工作,我找到了另一种解决原始问题的方法。您可以定义一个基接口类,它只包含您需要的方法。然后为您需要的方言实现具体的类。这允许一种类型的数据库用于测试,一种用于生产。

interface OrderRepository extends BaseRepository, CrudRepository<Order, UUID> {
  @Join(value = "product", type = Join.Type.LEFT_FETCH)
  Optional<Order> findById(UUID uuid)
}

@JdbcRepository(dialect = Dialect.H2)
@Requires(env = ["test"])
interface OrderRepositoryH2 extends OrderRepository, CrudRepository<Order, UUID> {
}

@JdbcRepository(dialect = Dialect.POSTGRES)
@Requires(env = ["dev"])
interface OrderRepositoryPostgres extends OrderRepository, CrudRepository<Order, UUID> {
}

OrderRepositoryH2 接口中不需要任何方法。Micronaut-data 可以很好地使用父接口中的方法。诀窍是不要在父接口中使用 @JdbcRepository 注释。

您可以创建所需的任何其他方言,但您必须确保 @Requires 注释在任何给定模式下只产生一个 bean。

我计划使用 H2 进行测试,并可以在需要时使用 Postgres 方言进行特殊测试运行。

抱歉对问题和评论有任何混淆。(我决定将此标记为答案,因为它解决了原始问题)。

于 2019-12-06T13:18:39.800 回答