복붙노트

[SPRING] 스프링 부트 애플리케이션에서 통합 테스트를 위해 임베디드 MongoDB를 어떻게 구성합니까?

SPRING

스프링 부트 애플리케이션에서 통합 테스트를 위해 임베디드 MongoDB를 어떻게 구성합니까?

작은 REST API를 노출하고 MongoDB의 인스턴스에서 데이터를 검색하는 상당히 간단한 Spring Boot 애플리케이션이 있습니다. MongoDB 인스턴스에 대한 쿼리는 스프링 데이터 기반 저장소를 통해 진행됩니다. 아래에 몇 가지 핵심 코드가 있습니다.

// Main application class
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@ComponentScan
@Import(MongoConfig.class)
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}
// Product repository with Spring data
public interface ProductRepository extends MongoRepository<Product, String> {

    Page<Product> findAll(Pageable pageable);

    Optional<Product> findByLineNumber(String lineNumber);
}
// Configuration for "live" connections
@Configuration
public class MongoConfig {

    @Value("${product.mongo.host}")
    private String mongoHost;

    @Value("${product.mongo.port}")
    private String mongoPort;

    @Value("${product.mongo.database}")
    private String mongoDatabase;

    @Bean(name="mongoClient")
    public MongoClient mongoClient() throws IOException {
        return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
    }

    @Autowired
    @Bean(name="mongoDbFactory")
    public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {
        return new SimpleMongoDbFactory(mongoClient, mongoDatabase);
    }

    @Autowired
    @Bean(name="mongoTemplate")
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, mongoDatabase);
    }
}
@Configuration
@EnableMongoRepositories
public class EmbeddedMongoConfig {

    private static final String DB_NAME = "integrationTest";
    private static final int DB_PORT = 12345;
    private static final String DB_HOST = "localhost";
    private static final String DB_COLLECTION = "products";

    private MongodExecutable mongodExecutable = null;

    @Bean(name="mongoClient")
    public MongoClient mongoClient() throws IOException {
        // Lots of calls here to de.flapdoodle.embed.mongo code base to 
        // create an embedded db and insert some JSON data
    }

    @Autowired
    @Bean(name="mongoDbFactory")
    public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {
        return new SimpleMongoDbFactory(mongoClient, DB_NAME);
    }

    @Autowired
    @Bean(name="mongoTemplate")
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, DB_NAME);
    }

    @PreDestroy
    public void shutdownEmbeddedMongoDB() {
        if (this.mongodExecutable != null) {
            this.mongodExecutable.stop();
        }
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestProductApplication.class)
@IntegrationTest
@WebAppConfiguration
public class WtrProductApplicationTests {

    @Test
    public void contextLoads() {
        // Tests empty for now
    }

}
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@ComponentScan
@Import(EmbeddedMongoConfig.class)
public class TestProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestProductApplication.class, args);
    }
}

따라서 여기에있는 아이디어는 통합 테스트를 (현재는 비어 있음) "라이브"가 아닌 내장 된 mongo 인스턴스에 연결시키는 것입니다. 그러나 작동하지 않습니다. 테스트가 Mongo의 "라이브"인스턴스에 연결되어있는 것을 볼 수 있습니다.이 작업을 종료하면 빌드가 여전히 Mongo의 라이브 인스턴스에 연결을 시도하면서 실패합니다. 아무도 이것이 왜 있는지 압니까? 임베디드 인스턴스에 연결하는 테스트는 어떻게합니까?

해결법

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

    1.이것은 나를 위해 작동합니다.

    이것은 나를 위해 작동합니다.

    테스트 클래스 :

        @RunWith(SpringJUnit4ClassRunner.class)
        @SpringApplicationConfiguration(classes = {
            Application.class, 
            TestMongoConfig.class // <--- Don't forget THIS
        })
        public class GameRepositoryTest {
    
            @Autowired
            private GameRepository gameRepository;
    
            @Test
            public void shouldCreateGame() {
                Game game = new Game(null, "Far Cry 3");
                Game gameCreated = gameRepository.save(game);
                assertEquals(gameCreated.getGameId(), gameCreated.getGameId());
                assertEquals(game.getName(), gameCreated.getName());
            }
    
        } 
    

    간단한 MongoDB 저장소 :

    public interface GameRepository extends MongoRepository<Game, String>     {
    
        Game findByName(String name);
    }
    

    MongoDB 테스트 구성 :

    import com.mongodb.Mongo;
    import com.mongodb.MongoClientOptions;
    import de.flapdoodle.embed.mongo.MongodExecutable;
    import de.flapdoodle.embed.mongo.MongodProcess;
    import de.flapdoodle.embed.mongo.MongodStarter;
    import de.flapdoodle.embed.mongo.config.IMongodConfig;
    import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
    import de.flapdoodle.embed.mongo.config.Net;
    import de.flapdoodle.embed.mongo.distribution.Version;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.mongo.MongoProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.io.IOException;
    
    @Configuration
    public class TestMongoConfig {
    
        @Autowired
        private MongoProperties properties;
    
        @Autowired(required = false)
        private MongoClientOptions options;
    
        @Bean(destroyMethod = "close")
        public Mongo mongo(MongodProcess mongodProcess) throws IOException {
            Net net = mongodProcess.getConfig().net();
            properties.setHost(net.getServerAddress().getHostName());
            properties.setPort(net.getPort());
            return properties.createMongoClient(this.options);
        }
    
        @Bean(destroyMethod = "stop")
        public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException {
            return mongodExecutable.start();
        }
    
        @Bean(destroyMethod = "stop")
        public MongodExecutable mongodExecutable(MongodStarter mongodStarter, IMongodConfig iMongodConfig) throws IOException {
            return mongodStarter.prepare(iMongodConfig);
        }
    
        @Bean
        public IMongodConfig mongodConfig() throws IOException {
            return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();
        }
    
        @Bean
        public MongodStarter mongodStarter() {
            return MongodStarter.getDefaultInstance();
        }
    
    }
    

    Pom.hml

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-mongodb</artifactId>
            </dependency>
            <dependency>
                <groupId>de.flapdoodle.embed</groupId>
                <artifactId>de.flapdoodle.embed.mongo</artifactId>
                <version>1.48.0</version>
                <scope>test</scope>
            </dependency>
    
  2. ==============================

    2.Spring Boot 1.3 버전부터는 즉시 사용 가능한 EmbeddedMongoAutoConfiguration 클래스가 있습니다. 즉, 구성 파일을 전혀 작성하지 않아도되며 여전히 변경할 수있는 사항을 변경하려는 경우입니다.

    Spring Boot 1.3 버전부터는 즉시 사용 가능한 EmbeddedMongoAutoConfiguration 클래스가 있습니다. 즉, 구성 파일을 전혀 작성하지 않아도되며 여전히 변경할 수있는 사항을 변경하려는 경우입니다.

    application.properties 파일에 추가되어야하는 가장 기본적이고 중요한 구성은 spring.data.mongodb.port = 0입니다 (0은 사용 가능한 구성 요소에서 무작위로 선택됨을 의미 함)

    자세한 내용은 다음을 확인하십시오 : Spring Boot Docs MongoDb

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

    3.나는 이전의 대답을 완료 할 것이다.

    나는 이전의 대답을 완료 할 것이다.

    Pom.hml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.2.RELEASE</version>
    </parent>
     ...
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <version>${embedded-mongo.version}</version>
        </dependency>
    

    MongoConfig

    @Configuration
    @EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
    public class MongoConfig{
    }
    
  4. ==============================

    4.버전 1.5.7에서는 다음과 같이 사용합니다.

    버전 1.5.7에서는 다음과 같이 사용합니다.

    @RunWith(SpringRunner.class)
    @DataMongoTest
    public class UserRepositoryTests {
    
        @Autowired
        UserRepository repository;
    
        @Before
        public void setUp() {
    
            User user = new User();
    
            user.setName("test");
            repository.save(user);
        }
    
        @Test
        public void findByName() {
            List<User> result = repository.findByName("test");
            assertThat(result).hasSize(1).extracting("name").contains("test");
        }
    
    }
    

            <dependency>
                <groupId>de.flapdoodle.embed</groupId>
                <artifactId>de.flapdoodle.embed.mongo</artifactId>
            </dependency>
    
  5. ==============================

    5.@ComponentScan을 사용하여 명시 적으로 확인하십시오. 기본적으로,

    @ComponentScan을 사용하여 명시 적으로 확인하십시오. 기본적으로,

    따라서 TestProductApplication과 ProductApplication 설정이 모두 같은 패키지에 있다면, Spring이 ProductApplication 설정을 컴포넌트 스캔하고이를 사용하는 것이 가능할 수있다.

    또한 '테스트'또는 '로컬'프로필에 테스트 몽고 콩을 넣고 테스트 클래스에서 @ActiveProfiles 주석을 사용하여 테스트 / 로컬 프로필을 사용하는 것이 좋습니다.

  6. from https://stackoverflow.com/questions/31568351/how-do-you-configure-embedded-mongdb-for-integration-testing-in-a-spring-boot-ap by cc-by-sa and MIT license