Заполните базу данных TestContainers в интеграционном тесте SpringBoot - PullRequest
0 голосов
/ 31 октября 2018

Я тестирую TestContainers и хотел бы знать, как заполнить базу данных, выполнив файл .sql, чтобы создать структуру и добавить несколько строк.

Как это сделать?

@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();

Большое спасибо заранее

Хуан Антонио

Ответы [ 5 ]

0 голосов
/ 01 апреля 2019

Существует еще один вариант, если вы определяете контейнер Postgres вручную, не добавляя причудливых тест-контейнеров JDBC-URL, не связанных напрямую с Spring. Образ Postgres позволяет связать каталог, содержащий сценарии sql, с объемом контейнера и автоматически выполнять их.

GenericContainer pgDb = new PostgreSQLContainer("postgres:9.4-alpine")
  .withFileSystemBind("migrations/sqls", "/docker-entrypoint-initdb.d",
    BindMode.READ_ONLY)

Также, если вам нужно что-то во время выполнения, вы всегда можете сделать pgDb.execInContainer("psql ....").

0 голосов
/ 18 ноября 2018

После некоторых обзоров, я думаю, что интересно рассмотреть примеры из Spring Data JDBC, в которых используются тестовые контейнеры:

Примечание: Использовать Java 8

git clone https://github.com/spring-projects/spring-data-jdbc.git
mvn clean install -Pall-dbs

Я создам простой проект, добавив несколько идей о предыдущем проекте.

Хуан Антонио

0 голосов
/ 06 ноября 2018

Spring Framework предоставляет возможность выполнения сценариев SQL для наборов тестов или для тестового модуля. Например:

@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"}) 
public void userTest {
   // execute code that relies on the test schema and test data
}

Вот документация .

Вы также можете взглянуть на Spring Test DBUnit , который предоставляет аннотации для заполнения вашей базы данных для тестового модуля. Он использует файлы набора данных XML.

@Test
@DatabaseSetup(value = "insert.xml")
@DatabaseTearDown(value = "insert.xml")
public void testInsert() throws Exception {
     // Inserts "insert.xml" before test execution
     // Remove "insert.xml" after test execution
}

Кроме того, вы можете взглянуть на DbSetup , который предоставляет свободный DSL-файл Java для заполнения вашей базы данных.

0 голосов
/ 13 ноября 2018

Вы можете использовать DatabaseRider , который использует DBUnit за кулисами, для заполнения тестовой базы данных и TestContainers в качестве источника тестовых данных. Ниже приведен пример теста, полный исходный код доступен на github здесь .

@RunWith(SpringRunner.class)
@SpringBootTest
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("integration-test")
@DBRider //enables database rider in spring tests 
@DBUnit(caseInsensitiveStrategy = Orthography.LOWERCASE) //https://stackoverflow.com/questions/43111996/why-postgresql-does-not-like-uppercase-table-names
public class SpringBootDBUnitIt {

    private static final PostgreSQLContainer postgres = new PostgreSQLContainer(); //creates the database for all tests on this file 

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private UserRepository userRepository;


    @BeforeClass
    public static void setupContainer() {
        postgres.start();
    }

    @AfterClass
    public static void shutdown() {
        postgres.stop();
    }


    @Test
    @DataSet("users.yml")
    public void shouldListUsers() throws Exception {
        assertThat(userRepository).isNotNull();
        assertThat(userRepository.count()).isEqualTo(3);
        assertThat(userRepository.findByEmail("springboot@gmail.com")).isEqualTo(new User(3));
    }

    @Test
    @DataSet("users.yml") //users table will be cleaned before the test because default seeding strategy
    @ExpectedDataSet("expected_users.yml")
    public void shouldDeleteUser() throws Exception {
        assertThat(userRepository).isNotNull();
        assertThat(userRepository.count()).isEqualTo(3);
        userRepository.delete(userRepository.findOne(2L));
        entityManager.flush();//can't SpringBoot autoconfigure flushmode as commit/always
        //assertThat(userRepository.count()).isEqualTo(2); //assertion is made by @ExpectedDataset
    }

    @Test
    @DataSet(cleanBefore = true)//as we didn't declared a dataset DBUnit wont clear the table
    @ExpectedDataSet("user.yml")
    public void shouldInsertUser() throws Exception {
        assertThat(userRepository).isNotNull();
        assertThat(userRepository.count()).isEqualTo(0);
        userRepository.save(new User("newUser@gmail.com", "new user"));
        entityManager.flush();//can't SpringBoot autoconfigure flushmode as commit/always
        //assertThat(userRepository.count()).isEqualTo(1); //assertion is made by @ExpectedDataset
    }

}

src/test/resources/application-integration-test.properties

spring.datasource.url=jdbc:tc:postgresql://localhost/test
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
#spring.jpa.properties.org.hibernate.flushMode=ALWAYS #doesn't take effect 
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

И, наконец, наборы данных:

src/test/resources/datasets/users.yml

users:
  - ID: 1
    EMAIL: "dbunit@gmail.com"
    NAME: "dbunit"
  - ID: 2
    EMAIL: "rmpestano@gmail.com"
    NAME: "rmpestano"
  - ID: 3
    EMAIL: "springboot@gmail.com"
    NAME: "springboot"

src/test/resources/datasets/expected_users.yml

users:
  - ID: 1
    EMAIL: "dbunit@gmail.com"
    NAME: "dbunit"
  - ID: 3
    EMAIL: "springboot@gmail.com"
    NAME: "springboot"

src/test/resources/datasets/user.yml

users:
  - ID: "regex:\\d+"
    EMAIL: "newUser@gmail.com"
    NAME: "new user"
0 голосов
/ 31 октября 2018

При использовании Spring Boot мне проще всего использовать поддержку JDBC URL TestContainers.

Вы можете создать application-integration-test.properties файл (обычно в src/test/resources с чем-то вроде этого:

spring.datasource.url=jdbc:tc:postgresql://localhost/myappdb
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
# This line is only needed if you are using flyway for database migrations
# and not using the default location of `db/migration`
spring.flyway.locations=classpath:db/migration/postgresql

Обратите внимание на часть :tc в URL JDBC.

Теперь вы можете написать модульный тест следующим образом:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("integration-test")
public class UserRepositoryIntegrationTest {
      @Autowired
      private MyObjectRepository repository;
      @PersistenceContext
      private EntityManager entityManager;
      @Autowired
      private JdbcTemplate template;

@Test
public void test() {
  // use your Spring Data repository, or the EntityManager or the JdbcTemplate to run your SQL and populate your database.
}

Примечание. Это объясняется в Практическом руководстве по созданию API-интерфейса с Spring Boot , глава 7, более подробно (Отказ от ответственности: я автор книги)

...