0

我有一个 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? :因为我希望进行基于组件的测试,而不是集成测试。

4

1 回答 1

0

好的,在@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 的 Mocked 版本,并将其添加到我的测试路径中,如下所示:

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

}

然后我们这样定义了一个 test-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上的注入和以前一样。但是,测试发生了一些变化,我们现在有:

  1. 删除了@RunAsClient
  2. 我们在 @Deployment 中包含 NoSQLUnit + Fongo jars
  3. 我们添加了上面的 test-beans.xml,以定义要启动的替代 bean。
  4. 我们@Inject -ed FakeDataStoreConnectionFactory并使用 setter 将我们的 mongoDatabase 设置为 In-Memory 定义的一个,其片段如下所示:

    @RunWith(Arquillian.class) 公共类 HelloResourceTest 扩展 AbstractTest{

    @ClassRule
    public static final InMemoryMongoDb IN_MEMORY_MONGO_DB = newInMemoryMongoDbRule().build();
    
    @Rule
    public MongoDbRule mongoDbRule = newMongoDbRule().defaultEmbeddedMongoDb("test");
    

    @Inject FakeDataStoreConnectionFactory fakeDataStoreConnectionFactory;

    @Before
    public void setupTest(){
        fakeDataStoreConnectionFactory.setMongoDatabase( mongoDbRule.getDatabaseOperation().connectionManager().getDatabase( "test" ) );
    
    }
    

    }

我现在面临的唯一问题是 @UsingDataSet 注释拒绝找到我的 .json 文件,它们位于 /path/to/my/test/file/initData.json 下。无论我把它们放在哪里,它仍然不起作用。

于 2018-08-08T09:18:03.250 回答