5

I have a standard spring boot application with this docker file:

FROM maven:latest AS maven

WORKDIR /usr/src/app
COPY . /usr/src/app
# Compile and package the application to an executable JAR
RUN mvn package

FROM amazoncorretto:17-alpine-jdk

ARG JAR_FILE=app.jar

WORKDIR /opt/app

# Copy the jar from the maven stage to the /opt/app directory of the current stage.
COPY --from=maven /usr/src/app/target/${JAR_FILE} /opt/app/

EXPOSE 8080

ENTRYPOINT ["java","-jar","app.jar"]

My application.properties file has the connection spring to my postgres db running in a docker container:

# datasource
spring.datasource.url=jdbc:postgresql://db:5432/myApp?currentSchema=gpclinic&createDatabaseIfNotExist=true
spring.datasource.username=uname
spring.datasource.password=pword

When I run:

docker build -t myApp .

I get a failure as the unit tests fail because the DB container is not running.

Will I need a Postgres container running to pass my tests? Or what is the best way to get around this?

java12399900
  • 1,485
  • 7
  • 26
  • 56
  • Do you really need to run the unit tests while the docker container is built? Wouldn't it make more sense to run the unit tests separate and only build your application's container when they pass? – MSpiller Mar 21 '23 at 09:54

4 Answers4

3

Roughly speaking, when you build your image under the hood docker creates a series of intermediate containers, one for every line in your Dockerfile.

You are trying to connect from one of this intermediate containers, the one which is packaging your application, to another container running Postgres in your host.

I am not sure if it will work - the subject had been broadly covered here in SO - but, if you are using MacOS or Windows, and your Postgres container exposes the port to the host, you could try modifying the connection string in your Spring properties and use the network address host.docker.internal to try reaching the database:

# datasource
spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/myApp?currentSchema=gpclinic&createDatabaseIfNotExist=true
spring.datasource.username=uname
spring.datasource.password=pword

You mentioned compose as well, but again I am not sure whether it is possible. Please, see this related SO question.

Having said that, please, be aware that the solution has different drawbacks, among others:

  • It makes your docker build not portable, think about building it in Linux or in a CI/CD system.
  • Probably you will need to set some kind of Spring profile or similar stuff for dealing with the properties value change.

I think that, as suggested in other answers, it is preferable to skip the unit tests execution while building your image. You can achieve this in several ways, for example (clean is not necessary, but I usually clean before packaging the application):

# Compile and package the application to an executable JAR
RUN mvn clean package -skipTests

Or:

# Compile and package the application to an executable JAR
RUN mvn clean package -Dmaven.test.skip=true

The same approach is addressed in this SO related question, for instance.

Following this approach, if you really need to run your tests, it is preferable to use a devoted step in a CI/CD system pipeline, for example, instead of running it in the docker build.

Finally, please, consider why you are accessing a database in a unit test: in my opinion, and please, forgive me, because SO answer shouldn't be opinion based, it is something that you can find in an integration test, for example, but I think it is not commonly used in unit tests.

Even in the case that using a database is a must, for simplicity, predictability, in order to improve portability and build isolation, please, consider use an in-memory one like H2 with the necessary information, and run your tests against it instead.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Nice, comprehensive answer! – ErikMD Mar 26 '23 at 22:37
  • 1
    Just adding a remark: `mvn clean package` can also be used as is (without any option) if the OP rename their JUnit test files involving an external deployment `SomeNameTest.java → SomeNameIT.java`, add the `maven-failsafe-plugin` Maven plugin, and use the `mvn clean verify -Dskip.surefire.tests=true` command (outside of the `Dockerfile`) to run the integrations tests (but not the unit tests, already run beforehand). – ErikMD Mar 26 '23 at 22:46
0

Skip tests while building the image, see Maven package/install without test (skip tests)

Once the image is built, you can run the tests by starting a container in an environment where a DB endpoint is available.

N1ngu
  • 2,862
  • 17
  • 35
0

I think the Below Answer might Help you

May be You can Add h2 database properites in a seperate properties file

application-test.properties.

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

And may be Change the Scope in original application.properties

spring.profiles.active=test

And you can Third Dependency for h2 Database as it will not be dependent on any other Database ..h2 Database runs in your JVM

<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

So in this Case you Dont need any container to Run the Tests...Once the Tests Passes your package will be built.

-1

As I understand you need insert endpoint of postgres where db in jdbc:postgresql://db:5432 Or if you have docker-compose.yml, service name of postgresql should be db

PaPu
  • 731
  • 7
  • 12