Reputation: 3928
Can anybody point it out, - what is the best approach to run RSpec tests on a Rails API app inside a Docker container (during the container build/run) ?
The aim is to be able to separate the development environment from other ones and to run tests only in development
mode, start Puma server only in staging, production
environments.
What is the right place to put bundle exec rspec
command, - in a separate entrypoint.sh
script, Directly in Dockerfile
, docker-compose.yml
file, or other solutions?
All the Googles results as well as Docker for Rails Developers book by PragProg have no examples and the only way to run the tests theys provide is to run them against an already running container.
Actually, my Dockerfile
looks like that:
FROM ruby:2.6.1
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends build-essential zip unzip libpq-dev libaio1 libaio-dev nodejs
ENV APP_HOME=/usr/src/app
ENV BUNDLE_PATH /gems
COPY . $APP_HOME
RUN echo "gem: --no-rdoc --no-ri" >> ~/.gemrc
WORKDIR $APP_HOME
RUN gem update --system
RUN gem install bundler
RUN bundle install
RUN ["chmod", "+x", "entrypoint.sh"]
CMD ["./entrypoint.sh"]
The entrypoint.sh
looks like that:
#!/bin/bash
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
./wait-for-it.sh ${DATABASE_HOST}:${DATABASE_PORT}
if [ -z "$RAILS_ENV" ]; then
echo "RAILS_ENV variable is not set, will use development by default"
bundle exec rails db:reset
bundle exec rails db:migrate
bundle exec rspec
else
bundle exec rails s -e $RAILS_ENV -p 3000 -b 0.0.0.0
fi
And finally, docker-compose.yml
:
version: '3.3'
services:
api:
build: ../..
ports:
- '3000:3000'
volumes:
- .:/usr/src/app
- gem_cache:/gems
env_file:
- ./env/database.env
- ./env/web.env
depends_on:
- database
# Keeps the stdin open, so we can attach to our app container's process and
# do stuff such as `byebug` or `binding.pry`:
stdin_open: true
# Allows us to send signals (CTRL+C, CTRL+P + CTRL+Q) into the container
tty: true
database:
image: postgres:9.6
env_file:
- ./env/database.env
volumes:
- db-data:/var/lib/postgresql/data
ports:
- 5432:5432
volumes:
db-data:
gem_cache:
Upvotes: 13
Views: 15071
Reputation: 1133
I found this worked for me:
# docker-compose.yml
# Shared config from my compose file
x-app_config: &app_config
build:
context: .
dockerfile: ./docker/Dockerfile
stdin_open: true
tty: true
environment: &env
RAILS_ENV: ${RAILS_ENV:-development}
volumes:
- .:/app
# ...
test:
<<: *app_config
environment:
<<: *env
RAILS_ENV: test
entrypoint: ["bundle", "exec", "rspec"]
Now run the test:
docker-compose run test ./specs/path/to/your/test_spec.rb
Hope that helps someone :)
Upvotes: 3
Reputation: 91
try
docker-compose run -e "RAILS_ENV=test" api bundle exec rspec spec/link/to/file.rb
Upvotes: 9
Reputation: 159790
You should run bundle exec rspec
on your host, before you run any Docker commands.
# Install and test the application locally
bundle install
bundle exec rspec
bundle exec rails server
# Great, it works; now package and run it in Docker
docker build -t ... .
docker run -p ... --net ... --name ... ...
You might find it useful to set up a partial Docker Compose environment with some dependencies. You can start these up before you run your test.
docker-compose up -d mysql redis
# Change config/settings.yml and config/database.yml to point at localhost
bundle exec rails rspec
You'll hit two practical problems trying to run tests in Docker.
If you try to run tests in the Dockerfile, that doesn't have access to any of the other services that might be defined in the same docker-compose.yml
file. In the particular case of Active Record, the application is actually unable to start, and you can't even run unit-type tests, without the database available. So you can't really run tests in the Dockerfile.
If you try to run tests at application startup, you need to include all of your test dependencies in the Docker image (which increases your image size and potential security attack surface). You need to decide whether you always want to run tests (which increases startup time, possibly significantly) or only run them sometimes (which is awkward in a plain Docker Compose setup, though pretty straightforward in more robust CI systems).
Upvotes: 2