Micronaut-Data JDBC - 用于测试和生产的多种方言
Micronaut-Data JDBC - Multiple Dialects for Test and Production
JDBC repositories 上的 Mirconaut 文档清楚地告诉我们,我们必须创建一个测试存储库来测试另一种方言。我认为这将是可管理的(例如用于生产的 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
}
为了使 find() 方法在 TestBookRepository 中可用,我不得不重复该方法(参见上面的注释行)。
有没有更好的方法避免重蹈覆辙?来自 CrudRepository 接口的方法在 TestBookRepository 中可用,没有问题。为什么 find() 方法的处理方式不同?
顺便说一句,我不想模拟测试存储库。我想针对 SQL 数据库测试由 Micronaut-Data 注入的存储库 'logic'。
这是针对 Micronaut Data 1.0.0.M5 的,使用 Groovy 作为来源。
您可以利用 Micronaut 环境为测试和生产创建不同的环境配置
并在 application-test.yml 中配置相应的数据源配置
并使用该数据源进行测试
经过一番努力,我找到了另一种方法来解决原来的问题。您可以定义一个基本接口 class,它只包含您需要的方法。然后为您需要的方言实施具体的 classes。这允许一种类型的数据库用于测试,一种用于生产。
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 方言进行特殊测试运行。
对于问题和评论的任何混淆,我们深表歉意。
(我决定将此标记为答案,因为它解决了原始问题)。
To make the find() method available in the TestBookRepository, I had
to repeat the method (see commented line above).
我无法重现该行为。为了做到这一点,我认为 java 编译器需要有一个导致这种情况的错误。
在 https://github.com/jeffbrown/mikehoustonrepository 查看项目。
// 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);
}
// 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{}
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);
}
}
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);
}
测试通过。
您可以看到用于其他环境 (BookRepository
) 的不同存储库正在用于测试 (TestBookRepository
)。
希望对您有所帮助。
JDBC repositories 上的 Mirconaut 文档清楚地告诉我们,我们必须创建一个测试存储库来测试另一种方言。我认为这将是可管理的(例如用于生产的 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
}
为了使 find() 方法在 TestBookRepository 中可用,我不得不重复该方法(参见上面的注释行)。
有没有更好的方法避免重蹈覆辙?来自 CrudRepository 接口的方法在 TestBookRepository 中可用,没有问题。为什么 find() 方法的处理方式不同?
顺便说一句,我不想模拟测试存储库。我想针对 SQL 数据库测试由 Micronaut-Data 注入的存储库 'logic'。
这是针对 Micronaut Data 1.0.0.M5 的,使用 Groovy 作为来源。
您可以利用 Micronaut 环境为测试和生产创建不同的环境配置 并在 application-test.yml 中配置相应的数据源配置 并使用该数据源进行测试
经过一番努力,我找到了另一种方法来解决原来的问题。您可以定义一个基本接口 class,它只包含您需要的方法。然后为您需要的方言实施具体的 classes。这允许一种类型的数据库用于测试,一种用于生产。
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 方言进行特殊测试运行。
对于问题和评论的任何混淆,我们深表歉意。 (我决定将此标记为答案,因为它解决了原始问题)。
To make the find() method available in the TestBookRepository, I had to repeat the method (see commented line above).
我无法重现该行为。为了做到这一点,我认为 java 编译器需要有一个导致这种情况的错误。
在 https://github.com/jeffbrown/mikehoustonrepository 查看项目。
// 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);
}
// 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{}
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);
}
}
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);
}
测试通过。
您可以看到用于其他环境 (BookRepository
) 的不同存储库正在用于测试 (TestBookRepository
)。
希望对您有所帮助。