diff --git a/README.md b/README.md index 81642d7..75d277c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,54 @@ Simple example of how to use MyBatis with annotations. -This example uses an embedded H2 database by default. This allows you to check the project out and immediately -run a clean build via Maven: +This example uses PostgreSQL with Testcontainers for automated testing. Tests automatically spin up a PostgreSQL +container, run the tests, and clean up - no manual database setup required! -``mvn clean verify -`` +## Quick Start -In addition, a MySQL Workbench file is included, along with a sample MyBatis generator file. You can use these -to explore more complex mappings - for example, to use the generator with an existing schema. +Simply run the tests via Maven. Testcontainers will automatically handle the PostgreSQL setup: + +```bash +mvn clean verify +``` + +**Note:** Docker must be running for tests to work, as Testcontainers manages PostgreSQL containers automatically. + +## Manual Local Development (Optional) + +If you want to run PostgreSQL manually for development, use the included docker-compose.yml: + +```bash +# Start PostgreSQL +docker-compose up -d + +# Stop PostgreSQL +docker-compose down + +# Stop and remove data +docker-compose down -v +``` + +The PostgreSQL instance will be available at `localhost:5432` with: +- Database: `testdb` +- Username: `test` +- Password: `test` ## Requirements -- [Maven 3.1.0](http://maven.apache.org/) -- Java 1.7+ +- [Maven 3.9.0+](http://maven.apache.org/) +- Java 21+ (LTS) +- Docker (for Testcontainers and docker-compose) + +## Dependencies + +This project uses the following major dependencies: +- MyBatis 3.5.19 +- JUnit 5 (Jupiter) 5.11.4 +- Log4j 2.24.0 +- PostgreSQL JDBC Driver 42.7.7 +- Testcontainers 1.20.1 + +## Additional Resources + +A MySQL Workbench file is included, along with a sample MyBatis generator file. You can use these +to explore more complex mappings - for example, to use the generator with an existing schema. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..078450b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + postgres: + image: postgres:16-alpine + container_name: mybatis-postgres + environment: + POSTGRES_DB: testdb + POSTGRES_USER: test + POSTGRES_PASSWORD: test + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U test"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: diff --git a/pom.xml b/pom.xml index 6e04e74..64d7e7f 100644 --- a/pom.xml +++ b/pom.xml @@ -12,29 +12,59 @@ UTF-8 + 21 + 21 + 5.11.4 + 3.5.19 + 2.24.0 + 42.7.7 + 1.20.1 - junit - junit - 4.12 + org.junit.jupiter + junit-jupiter + ${junit.version} test org.mybatis mybatis - 3.3.0 + ${mybatis.version} - log4j - log4j - 1.2.17 + org.apache.logging.log4j + log4j-core + ${log4j.version} - com.h2database - h2 - 1.4.189 + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.postgresql + postgresql + ${postgresql.version} + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + org.testcontainers + postgresql + ${testcontainers.version} + test + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test @@ -45,62 +75,62 @@ org.apache.maven.plugins maven-site-plugin - 3.4 + 4.0.0-M16 org.apache.maven.plugins maven-surefire-plugin - 2.18.1 + 3.5.2 org.apache.maven.plugins maven-jar-plugin - 2.6 + 3.4.2 org.apache.maven.plugins maven-antrun-plugin - 1.8 + 3.1.0 org.apache.maven.plugins maven-assembly-plugin - 2.5.4 + 3.7.1 org.apache.maven.plugins maven-release-plugin - 2.5.2 + 3.1.1 - org.apache.maven + org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + 3.7.0 org.apache.maven.plugins maven-dependency-plugin - 2.10 + 3.8.1 org.apache.maven.plugins maven-clean-plugin - 2.6.1 + 3.4.0 org.apache.maven.plugins maven-resources-plugin - 2.7 + 3.3.1 org.apache.maven.plugins maven-deploy-plugin - 2.8.2 + 3.1.3 org.apache.maven.plugins maven-install-plugin - 2.5.2 + 3.1.3 @@ -109,11 +139,9 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.13.0 - - 1.8 - 1.8 + 21 @@ -131,7 +159,7 @@ org.apache.maven.doxia doxia-module-markdown - 1.6 + 2.0.0-M12 @@ -145,15 +173,15 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + 3.7.0 + - you should use standard version numbering too! https://www.mojohaus.org/versions/versions-maven-plugin/version-rules.html --> org.codehaus.mojo versions-maven-plugin - 2.1 + 2.18.0 diff --git a/src/main/java/com/example/mybatis/TransactionTokenMapper.java b/src/main/java/com/example/mybatis/TransactionTokenMapper.java index a3a1548..5a82791 100644 --- a/src/main/java/com/example/mybatis/TransactionTokenMapper.java +++ b/src/main/java/com/example/mybatis/TransactionTokenMapper.java @@ -17,7 +17,7 @@ public interface TransactionTokenMapper { * of functionality to both intialize the database for test purposes as well as validating the bindings. For * example, a standard schema() method and a validate() method, called as part of the factory setup. */ - @Update("create table trans_token (id bigint auto_increment, trans_id varchar, token_id varchar)") + @Update("create table trans_token (id bigserial primary key, trans_id varchar, token_id varchar)") void schema(); @Select({ diff --git a/src/main/resources/Configuration.xml b/src/main/resources/Configuration.xml index 61aacba..39d663b 100644 --- a/src/main/resources/Configuration.xml +++ b/src/main/resources/Configuration.xml @@ -9,20 +9,12 @@ - - - - - - - - - - - - - - + + + + + + diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml deleted file mode 100644 index fc39356..0000000 --- a/src/main/resources/log4j.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..32d4198 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/com/example/mybatis/AppTest.java b/src/test/java/com/example/mybatis/AppTest.java index f482dad..736f871 100644 --- a/src/test/java/com/example/mybatis/AppTest.java +++ b/src/test/java/com/example/mybatis/AppTest.java @@ -1,20 +1,50 @@ package com.example.mybatis; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.ibatis.datasource.pooled.PooledDataSource; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Testcontainers public class AppTest { - @BeforeClass + @Container + static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:16-alpine") + .withDatabaseName("testdb") + .withUsername("test") + .withPassword("test"); + + @BeforeAll static public void testApp() { - App.init(); + // Create a custom configuration with Testcontainers PostgreSQL + PooledDataSource dataSource = new PooledDataSource(); + dataSource.setDriver(postgres.getDriverClassName()); + dataSource.setUrl(postgres.getJdbcUrl()); + dataSource.setUsername(postgres.getUsername()); + dataSource.setPassword(postgres.getPassword()); + + Environment environment = new Environment("development", new JdbcTransactionFactory(), dataSource); + Configuration config = new Configuration(environment); + config.setUseGeneratedKeys(true); + config.addMapper(TransactionTokenMapper.class); + + App.factory = new SqlSessionFactoryBuilder().build(config); assertNotNull(App.factory); @@ -30,13 +60,13 @@ static public void testApp() { private TransactionTokenMapper mapper = null; private SqlSession session = null; - @Before + @BeforeEach public void setupSession() { session = App.factory.openSession(); // This obtains a database connection! mapper = session.getMapper(TransactionTokenMapper.class); } - @After + @AfterEach public void closeSession() { session.commit(); // This commits the data to the database. Required even if auto-commit=true session.close(); // This releases the connection