无法使用 NoSqlUnit 访问内存 mongodb
Not able to access in-memory mongodb using NoSqlUnit
我有一个 arquillian 组件测试,我想在其中使用使用 NoSqlUnit 的内存中 MongoDB (Fongo) 数据库。我正在使用 @Producer 来定义我的 DataStoreConnection,我正在 Java SE 8 上使用 Eclipse MicroProfile。
问题是在启动内存数据库后,在进行端点测试时我无法在我的代码中以编程方式访问它。
我有一个这样的 DataStoreConnectionProducer:
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class DataStoreConnectionProducer {
private MongoClient mongoClient;
private static final Config config = ConfigProvider.getConfig();
@Produces
public MongoDatabase createMongoClient(){
final String DB_PATH = config.getValue( "mongodb.path", String.class );
final int DB_PORT = config.getValue( "mongodb.port", Integer.class );
final String DB_NAME = config.getValue( "mongodb.dbname", String.class );
if( DB_NAME.equals( "test" ) )
return new MongoClient().getDatabase(DB_NAME);
else
return new MongoClient( DB_PATH, DB_PORT ).getDatabase( DB_NAME );
}
}
我的 GreetingDAO 正在使用
注入 MongoDatabase
@Inject MongoDatabase mongoDatabase;
我的资源看起来是这样的:
@Path( "/greetings" )
public class HelloResource {
@Inject
private GreetingDAO greetingDAO;
@Inject
private GreetingService greetingService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getGreeting (){
return Response.ok(greetingDAO.findAll(), MediaType.APPLICATION_JSON).build();
}
@GET
@Path( "{id}" )
@Produces( MediaType.APPLICATION_JSON )
public Response getGreetingById( @PathParam( "id" ) String greetingId ){
try {
return Response.ok( greetingDAO.findByID( greetingId.toLowerCase() ), MediaType.APPLICATION_JSON ).build();
}catch ( NoSuchElementException ex ){
ex.printStackTrace();
return Response.status( 404 ).build();
}
}
最后是我的 Arquillian 测试:
@RunWith( Arquillian.class )
@RunAsClient
public class HelloResourceTest extends AbstractTest{
private static final String DB_NAME = "test";
@ClassRule
public static final InMemoryMongoDb inMemoryMongoDb =
newInMemoryMongoDbRule().targetPath( "localhost" ).build();
@Rule
public MongoDbRule embeddedMongoDbRule = newMongoDbRule()
.defaultEmbeddedMongoDb(DB_NAME);
@Inject MongoClient mongoClient;
@Deployment
public static WebArchive createDeployment () {
WebArchive war = createBasicDeployment()
.addClasses(
HelloResource.class,
GreetingDAO.class,
GreetingService.class,
Greeting.class,
DAO.class,
DataStoreConnectionProducer.class
);
System.out.println( war.toString(true) );
return war;
}
private MongoDatabase getFongoDataBase(){
return mongoClient.getDatabase( DB_NAME );
}
这几乎就是我开始感到困惑的地方。知道 Fongo 是一个内存数据库,肯定没有远程访问它的方法吗?相反,我肯定必须将其提供给我的 DataStoreConnectionProducer 或以某种方式将其注入我的 GreetingDAO,以便使用 FongoDB 而不是 @Producer 尝试连接到我的托管 MongoDB.
您可能会问一个问题:为什么不使用托管 MongoDB?
回答:因为我想做基于组件的测试,而不是集成测试。
好的,在@lordofthejars 的一些指导下,我设法将 NoSQLUnit 与内存 MongoDB (Fongo) 一起用于我的资源测试。
但是我不得不做一些改变:
DataStoreConnectionProducer
它做了它应该做的,但在它的实现中不是很容易测试,我让它变得更冗长:
@Singleton
public class DataStoreConnectionFactory {
private MongoDatabase mongoDatabase;
@PostConstruct
public void init(){
this.mongoDatabase = establishConnection();
}
protected MongoDatabase establishConnection(){
final Config config = ConfigProvider.getConfig();
final String DB_PATH = config.getValue( "mongodb.path", String.class );
final int DB_PORT = config.getValue( "mongodb.port", Integer.class );
final String DB_NAME = config.getValue( "mongodb.dbname", String.class );
return new MongoClient( DB_PATH, DB_PORT ).getDatabase( DB_NAME );
}
@Produces
public MongoDatabase getMongoDatabase(){
return this.mongoDatabase;
}
}
我还创建了这个 Producer/Factory 的模拟版本并将其添加到我的测试路径中,它看起来如下:
@Singleton
@Alternative
public class FakeDataStoreConnectionFactory {
private MongoDatabase mongoDatabase;
@PostConstruct
public void init(){
this.mongoDatabase = establishConnection();
}
protected MongoDatabase establishConnection(){
return Mockito.mock(MongoDatabase.class);
}
@Produces
public MongoDatabase getMongoDatabase(){
return this.mongoDatabase;
}
public void setMongoDatabase(MongoDatabase db){
this.mongoDatabase = db;
}
}
然后我们这样定义了一个测试-beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<alternatives>
<class>path.to.my.test.folder.containing.FakeDataStoreConnectionFactory</class>
</alternatives>
</beans>
GreetingDAO 上的注入和以前一样。然而,测试有一点变化,我们现在有:
- 删除了 @RunAsClient
- 我们在 @Deployment
中包含 NoSQLUnit + Fongo jar
- 我们添加了上面的测试-beans.xml,以定义要启动的替代 bean。
我们 @Inject-ed FakeDataStoreConnectionFactory 并使用 setter 将我们的 mongoDatabase 设置为In-Memory 定义的一个,其片段如下所示:
@RunWith(Arquillian.class)
public class HelloResourceTest 扩展了 AbstractTest{
@ClassRule
public static final InMemoryMongoDb IN_MEMORY_MONGO_DB = newInMemoryMongoDbRule().build();
@Rule
public MongoDbRule mongoDbRule = newMongoDbRule().defaultEmbeddedMongoDb("test");
@注入
FakeDataStoreConnectionFactory fakeDataStoreConnectionFactory;
@Before
public void setupTest(){
fakeDataStoreConnectionFactory.setMongoDatabase( mongoDbRule.getDatabaseOperation().connectionManager().getDatabase( "test" ) );
}
}
我现在面临的唯一问题是@UsingDataSet 注释拒绝找到我的 .json 文件,它们位于 /path/to/my/test/file/initData.json 下。无论我把它们放在哪里,它仍然不起作用。
我有一个 arquillian 组件测试,我想在其中使用使用 NoSqlUnit 的内存中 MongoDB (Fongo) 数据库。我正在使用 @Producer 来定义我的 DataStoreConnection,我正在 Java SE 8 上使用 Eclipse MicroProfile。
问题是在启动内存数据库后,在进行端点测试时我无法在我的代码中以编程方式访问它。
我有一个这样的 DataStoreConnectionProducer:
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class DataStoreConnectionProducer {
private MongoClient mongoClient;
private static final Config config = ConfigProvider.getConfig();
@Produces
public MongoDatabase createMongoClient(){
final String DB_PATH = config.getValue( "mongodb.path", String.class );
final int DB_PORT = config.getValue( "mongodb.port", Integer.class );
final String DB_NAME = config.getValue( "mongodb.dbname", String.class );
if( DB_NAME.equals( "test" ) )
return new MongoClient().getDatabase(DB_NAME);
else
return new MongoClient( DB_PATH, DB_PORT ).getDatabase( DB_NAME );
}
}
我的 GreetingDAO 正在使用
注入 MongoDatabase@Inject MongoDatabase mongoDatabase;
我的资源看起来是这样的:
@Path( "/greetings" )
public class HelloResource {
@Inject
private GreetingDAO greetingDAO;
@Inject
private GreetingService greetingService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getGreeting (){
return Response.ok(greetingDAO.findAll(), MediaType.APPLICATION_JSON).build();
}
@GET
@Path( "{id}" )
@Produces( MediaType.APPLICATION_JSON )
public Response getGreetingById( @PathParam( "id" ) String greetingId ){
try {
return Response.ok( greetingDAO.findByID( greetingId.toLowerCase() ), MediaType.APPLICATION_JSON ).build();
}catch ( NoSuchElementException ex ){
ex.printStackTrace();
return Response.status( 404 ).build();
}
}
最后是我的 Arquillian 测试:
@RunWith( Arquillian.class )
@RunAsClient
public class HelloResourceTest extends AbstractTest{
private static final String DB_NAME = "test";
@ClassRule
public static final InMemoryMongoDb inMemoryMongoDb =
newInMemoryMongoDbRule().targetPath( "localhost" ).build();
@Rule
public MongoDbRule embeddedMongoDbRule = newMongoDbRule()
.defaultEmbeddedMongoDb(DB_NAME);
@Inject MongoClient mongoClient;
@Deployment
public static WebArchive createDeployment () {
WebArchive war = createBasicDeployment()
.addClasses(
HelloResource.class,
GreetingDAO.class,
GreetingService.class,
Greeting.class,
DAO.class,
DataStoreConnectionProducer.class
);
System.out.println( war.toString(true) );
return war;
}
private MongoDatabase getFongoDataBase(){
return mongoClient.getDatabase( DB_NAME );
}
这几乎就是我开始感到困惑的地方。知道 Fongo 是一个内存数据库,肯定没有远程访问它的方法吗?相反,我肯定必须将其提供给我的 DataStoreConnectionProducer 或以某种方式将其注入我的 GreetingDAO,以便使用 FongoDB 而不是 @Producer 尝试连接到我的托管 MongoDB.
您可能会问一个问题:为什么不使用托管 MongoDB? 回答:因为我想做基于组件的测试,而不是集成测试。
好的,在@lordofthejars 的一些指导下,我设法将 NoSQLUnit 与内存 MongoDB (Fongo) 一起用于我的资源测试。
但是我不得不做一些改变:
DataStoreConnectionProducer 它做了它应该做的,但在它的实现中不是很容易测试,我让它变得更冗长:
@Singleton
public class DataStoreConnectionFactory {
private MongoDatabase mongoDatabase;
@PostConstruct
public void init(){
this.mongoDatabase = establishConnection();
}
protected MongoDatabase establishConnection(){
final Config config = ConfigProvider.getConfig();
final String DB_PATH = config.getValue( "mongodb.path", String.class );
final int DB_PORT = config.getValue( "mongodb.port", Integer.class );
final String DB_NAME = config.getValue( "mongodb.dbname", String.class );
return new MongoClient( DB_PATH, DB_PORT ).getDatabase( DB_NAME );
}
@Produces
public MongoDatabase getMongoDatabase(){
return this.mongoDatabase;
}
}
我还创建了这个 Producer/Factory 的模拟版本并将其添加到我的测试路径中,它看起来如下:
@Singleton
@Alternative
public class FakeDataStoreConnectionFactory {
private MongoDatabase mongoDatabase;
@PostConstruct
public void init(){
this.mongoDatabase = establishConnection();
}
protected MongoDatabase establishConnection(){
return Mockito.mock(MongoDatabase.class);
}
@Produces
public MongoDatabase getMongoDatabase(){
return this.mongoDatabase;
}
public void setMongoDatabase(MongoDatabase db){
this.mongoDatabase = db;
}
}
然后我们这样定义了一个测试-beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<alternatives>
<class>path.to.my.test.folder.containing.FakeDataStoreConnectionFactory</class>
</alternatives>
</beans>
GreetingDAO 上的注入和以前一样。然而,测试有一点变化,我们现在有:
- 删除了 @RunAsClient
- 我们在 @Deployment 中包含 NoSQLUnit + Fongo jar
- 我们添加了上面的测试-beans.xml,以定义要启动的替代 bean。
我们 @Inject-ed FakeDataStoreConnectionFactory 并使用 setter 将我们的 mongoDatabase 设置为In-Memory 定义的一个,其片段如下所示:
@RunWith(Arquillian.class) public class HelloResourceTest 扩展了 AbstractTest{
@ClassRule public static final InMemoryMongoDb IN_MEMORY_MONGO_DB = newInMemoryMongoDbRule().build(); @Rule public MongoDbRule mongoDbRule = newMongoDbRule().defaultEmbeddedMongoDb("test");
@注入 FakeDataStoreConnectionFactory fakeDataStoreConnectionFactory;
@Before public void setupTest(){ fakeDataStoreConnectionFactory.setMongoDatabase( mongoDbRule.getDatabaseOperation().connectionManager().getDatabase( "test" ) ); }
}
我现在面临的唯一问题是@UsingDataSet 注释拒绝找到我的 .json 文件,它们位于 /path/to/my/test/file/initData.json 下。无论我把它们放在哪里,它仍然不起作用。