복붙노트

[MONGODB] MongoDB를 가진 유닛 테스트

MONGODB

MongoDB를 가진 유닛 테스트

선택의 내 데이터베이스 MongoDB를합니다. 나는 클라이언트 응용 프로그램에서 추상적 인 구현 세부 사항에 대한 데이터 계층 API를 쓰고 있어요 - 나는 기본적으로 하나의 공용 인터페이스 (IDL의 역할을하는 객체)를 제공하고 있습니다입니다.

나는 TDD 방식에 가서 내 논리를 테스트하고있다. 각 단위 시험 전에 @Before 방법은, 데이터베이스를 작성하는 싱글이라 테스트 완료가 @After 방법은 데이터베이스를 h라고 할 때, 이는 후에. 이것은 단위 테스트들 사이에서 독립을 촉진하는 데 도움이됩니다.

문맥 질의를 수행하는 거의 모든 단위 테스트, 즉, 손을 삽입하기 전에 발생 로직의 일종을 필요로한다. 각 단위 테스트에 전구체 논리로이 방법을 사용하는 것이 잘못된 것 같다, 아직 - 내 공용 인터페이스는 삽입 방법을 제공합니다.

정말 내가 메커니즘을 조롱 어떤 종류의 필요, 그러나, 나는 조롱 프레임 워크를 사용한 경험이 많지 않은, 구글이 MongoDB를 사용할 수있는 조롱 프레임 워크 일 다시 아무 것도 반환하지 않습니다 것으로 보인다.

다른 사람은이 상황에서 어떻게해야합니까? 어떻게 사람들의 단위 테스트 코드를 어떻게하는지 그 데이터베이스와 상호 작용?

또한, 외부 구성 파일에 정의 된 데이터베이스에 내 공개 인터페이스 커넥트가 - 다시, 조롱 어떤 종류의 혜택을 누릴 것입니다 상황을 - 내 단위 테스트를 위해이 연결을 사용하는 잘못된 것 같습니다?

해결법

  1. ==============================

    1.sbridges이 게시물에 썼던 것처럼 논리의 데이터 액세스를 추상화하는 전용 서비스 (때로는 저장소 또는 DAO로 알려진)를 가지고 나쁜 생각이다. 그럼 당신은 DAO의 모의를 제공하여 논리를 테스트 할 수있다.

    sbridges이 게시물에 썼던 것처럼 논리의 데이터 액세스를 추상화하는 전용 서비스 (때로는 저장소 또는 DAO로 알려진)를 가지고 나쁜 생각이다. 그럼 당신은 DAO의 모의를 제공하여 논리를 테스트 할 수있다.

    내가 할 또 다른 방법은 몽고 객체 (예를 들어, PowerMockito)의 모의를 생성하고 해당 결과를 반환하는 것입니다. 데이터베이스 단위 테스트에서 작동하지만 더 올바른 쿼리가, 데이타베이스에 전송 된 경우 테스트해야합니다 이상 경우에 당신은 시험이 없기 때문에.

    Mongo mongo = PowerMockito.mock(Mongo.class);
    DB db = PowerMockito.mock(DB.class);
    DBCollection dbCollection = PowerMockito.mock(DBCollection.class);
    
    PowerMockito.when(mongo.getDB("foo")).thenReturn(db);
    PowerMockito.when(db.getCollection("bar")).thenReturn(dbCollection);
    
    MyService svc = new MyService(mongo); // Use some kind of dependency injection
    svc.getObjectById(1);
    
    PowerMockito.verify(dbCollection).findOne(new BasicDBObject("_id", 1));
    

    그것은 또한 옵션이 될 것입니다. 물론 상기 모의 객체의 생성 및 적절한 개체로 반환 바로 위에서 예로서 코딩된다.

  2. ==============================

    2.기술적 데이터베이스 (NoSQL에 또는 기타) 테스트는 외부 시스템과의 상호 작용을 테스트뿐 아니라 코드의 고립 된 단위 테스트로, 단위 테스트하지 않습니다에 그 이야기를 테스트합니다. 그러나 데이터베이스에 그 이야기는 종종 매우 유용하며, 종종 다른 단위 테스트를 실행하는 빠른 충분히 테스트합니다.

    기술적 데이터베이스 (NoSQL에 또는 기타) 테스트는 외부 시스템과의 상호 작용을 테스트뿐 아니라 코드의 고립 된 단위 테스트로, 단위 테스트하지 않습니다에 그 이야기를 테스트합니다. 그러나 데이터베이스에 그 이야기는 종종 매우 유용하며, 종종 다른 단위 테스트를 실행하는 빠른 충분히 테스트합니다.

    보통 나는 데이터베이스를 처리하기위한 모든 로직을 캡슐화하는 서비스 인터페이스 (예를 들어 UserService)가 있습니다. UserService에 의존하는 코드는 UserService의 조롱 버전을 사용할 수 있습니다 쉽게 테스트됩니다.

    서비스의 구현을 테스트 할 때 그 몽고, (예를 들어 MongoUserService)이 /가 시작됩니다 일부 자바 코드를 작성 로컬 컴퓨터에 몽고 프로세스를 중지하고 MongoUserService가 연결이 일부에 대한이 질문을보고 가장 쉬운 방법입니다 회담 노트.

    당신은 발생하기 쉬운 오류가 너무, 당신은 정말 실제 데이터베이스와의 상호 작용 성 테스트로 원하는 테스트하지 않는 일반적으로 MongoUserService을 테스트하는 동안 데이터베이스의 기능을 조롱하려고 노력하지만, 수 있습니다. MongoUserService에 대한 테스트를 작성 때, 각 시험에 대한 데이터베이스 상태를 설정합니다. 데이터베이스와 그렇게하기위한 프레임 워크의 예를 들어 DbUnit을 봐.

  3. ==============================

    3.나는 자바에서 MongoDB를 가짜 구현을 썼다 : 몽고 - 자바 서버

    나는 자바에서 MongoDB를 가짜 구현을 썼다 : 몽고 - 자바 서버

    기본값은 쉽게 단위 및 통합 테스트에 사용할 수있는 메모리 백엔드입니다.

    MongoServer server = new MongoServer(new MemoryBackend());
    // bind on a random local port
    InetSocketAddress serverAddress = server.bind();
    
    MongoClient client = new MongoClient(new ServerAddress(serverAddress));
    
    DBCollection coll = client.getDB("testdb").getCollection("testcoll");
    // creates the database and collection in memory and inserts the object
    coll.insert(new BasicDBObject("key", "value"));
    
    assertEquals(1, collection.count());
    assertEquals("value", collection.findOne().get("key"));
    
    client.close();
    server.shutdownNow();
    
  4. ==============================

    4.오늘은 내가 가장 좋은 방법은 파이썬에서 사용 testcontainers 라이브러리 (자바) 또는 testcontainers - 파이썬 포트에 생각합니다. 그것은 단위 테스트와 도커 이미지를 사용할 수 있습니다. 자바 코드 만 인스턴스화 GenericContainer 개체 (예) 용기를 실행하려면 :

    오늘은 내가 가장 좋은 방법은 파이썬에서 사용 testcontainers 라이브러리 (자바) 또는 testcontainers - 파이썬 포트에 생각합니다. 그것은 단위 테스트와 도커 이미지를 사용할 수 있습니다. 자바 코드 만 인스턴스화 GenericContainer 개체 (예) 용기를 실행하려면 :

    GenericContainer mongo = new GenericContainer("mongo:latest")
        .withExposedPorts(27017);
    
    MongoClient mongoClient = new MongoClient(mongo.getContainerIpAddress(), mongo.getMappedPort(27017));
    MongoDatabase database = mongoClient.getDatabase("test");
    MongoCollection<Document> collection = database.getCollection("testCollection");
    
    Document doc = new Document("name", "foo")
            .append("value", 1);
    collection.insertOne(doc);
    
    Document doc2 = collection.find(new Document("name", "foo")).first();
    assertEquals("A record can be inserted into and retrieved from MongoDB", 1, doc2.get("value"));
    

    파이썬 (예)에 :

    mongo = GenericContainer('mongo:latest')
    mongo.with_bind_ports(27017, 27017)
    
    with mongo_container:
        def connect():
            return MongoClient("mongodb://{}:{}".format(mongo.get_container_host_ip(),
                                                        mongo.get_exposed_port(27017)))
    
        db = wait_for(connect).primer
        result = db.restaurants.insert_one(
            # JSON as dict object
        )
    
        cursor = db.restaurants.find({"field": "value"})
        for document in cursor:
            print(document)
    
  5. ==============================

    5.나는 아무도 fakemongo 지금까지 사용하는 것이 좋습니다하지 놀라게하고있다. 그것은 꽤 잘 에뮬레이트 몽고 클라이언트, 그리고 테스트와 같은 JVM에있는 모든 실행 - 어떤 외부 시스템의 상호 작용이 발생하지 않기 때문에 통합 테스트가 기술적으로 훨씬 더 가까운 사실 "단위 테스트"에 강력되고, 그래서. 그것은 단위 테스트에 SQL 코드를 포함 H2를 사용하는 것과 같습니다. 내가 단위 테스트에 fakemongo 사용 매우 행복했다 그 엔드 - 투 - 엔드 방식으로 테스트 데이터베이스 통합 코드. 테스트 스프링 컨텍스트에서이 구성을 고려 :

    나는 아무도 fakemongo 지금까지 사용하는 것이 좋습니다하지 놀라게하고있다. 그것은 꽤 잘 에뮬레이트 몽고 클라이언트, 그리고 테스트와 같은 JVM에있는 모든 실행 - 어떤 외부 시스템의 상호 작용이 발생하지 않기 때문에 통합 테스트가 기술적으로 훨씬 더 가까운 사실 "단위 테스트"에 강력되고, 그래서. 그것은 단위 테스트에 SQL 코드를 포함 H2를 사용하는 것과 같습니다. 내가 단위 테스트에 fakemongo 사용 매우 행복했다 그 엔드 - 투 - 엔드 방식으로 테스트 데이터베이스 통합 코드. 테스트 스프링 컨텍스트에서이 구성을 고려 :

    @Configuration
    @Slf4j
    public class FongoConfig extends AbstractMongoConfiguration {
        @Override
        public String getDatabaseName() {
            return "mongo-test";
        }
    
        @Override
        @Bean
        public Mongo mongo() throws Exception {
            log.info("Creating Fake Mongo instance");
            return new Fongo("mongo-test").getMongo();
        }
    
        @Bean
        @Override
        public MongoTemplate mongoTemplate() throws Exception {
            return new MongoTemplate(mongo(), getDatabaseName());
        }
    
    }
    

    이것으로 당신은 봄 컨텍스트에서 MongoTemplate를 사용하는 코드를 테스트 할 수 있으며, NoSQL의 단위, jsonunit 등과 결합하여 당신은 커버 몽고의 쿼리 코드가 강력한 단위 테스트를 얻을.

    @Test
    @UsingDataSet(locations = {"/TSDR1326-data/TSDR1326-subject.json"}, loadStrategy = LoadStrategyEnum.CLEAN_INSERT)
    @DatabaseSetup({"/TSDR1326-data/dbunit-TSDR1326.xml"})
    public void shouldCleanUploadSubjectCollection() throws Exception {
        //given
        JobParameters jobParameters = new JobParametersBuilder()
                .addString("studyId", "TSDR1326")
                .addString("execId", UUID.randomUUID().toString())
                .toJobParameters();
    
        //when
        //next line runs a Spring Batch ETL process loading data from SQL DB(H2) into Mongo
        final JobExecution res = jobLauncherTestUtils.launchJob(jobParameters);
    
        //then
        assertThat(res.getExitStatus()).isEqualTo(ExitStatus.COMPLETED);
        final String resultJson = mongoTemplate.find(new Query().with(new Sort(Sort.Direction.ASC, "topLevel.subjectId.value")),
                DBObject.class, "subject").toString();
    
        assertThatJson(resultJson).isArray().ofLength(3);
        assertThatDateNode(resultJson, "[0].topLevel.timestamp.value").isEqualTo(res.getStartTime());
    
        assertThatNode(resultJson, "[0].topLevel.subjectECode.value").isStringEqualTo("E01");
        assertThatDateNode(resultJson, "[0].topLevel.subjectECode.timestamp").isEqualTo(res.getStartTime());
    
        ... etc
    }
    

    나는 몽고 3.4 드라이버 문제없이 fakemongo 사용하고, 지역 사회는 지원 3.6 드라이버 (https://github.com/fakemongo/fongo/issues/316) 버전을 출시 정말 가깝습니다.

  6. from https://stackoverflow.com/questions/7413985/unit-testing-with-mongodb by cc-by-sa and MIT license