Docker,Docker compose - 如何运行 RSpec 测试。

13

有没有人能指出来,在Docker容器内(在容器构建/运行期间)运行Rails API应用程序的RSpec测试的最佳方法是什么?

目的是能够将开发环境与其他环境分离,并仅在development模式下运行测试,在staging、production环境中仅启动Puma服务器。

bundle exec rspec命令放置的正确位置是什么,- 在单独的entrypoint.sh脚本中,直接在Dockerfiledocker-compose.yml文件中,还是其他解决方案?

所有谷歌的结果以及PragProg的Docker for Rails Developers书籍都没有示例,唯一的运行测试的方式是针对已经运行的容器运行它们。

实际上,我的Dockerfile看起来像这样:

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"]

entrypoint.sh的内容如下:

#!/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

最后,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:

这个实际上不起作用,还是说这是一个关于你写的方式是否可接受的问题? - streetlogics
@streetlogics,它实际上没有起作用,DB主机无法访问。这只是设置的一部分。因为镜像已经构建并推送到Rancher。所以它既可以是可接受的方式,也可以不是。也许为了运行测试,我们不必使用Docker,而是使用其他管道或类似的东西,具体取决于可用的工具(GitLab、GitHub等)。我将创建一个单独的经典Docker应用程序,看看它是否有效。 - belgoros
从多篇文章中我发现,在Docker容器中运行测试并不是一个好的选择——有时候会花费很长时间,而且镜像构建也需要很长时间。构建镜像的主要目的是提供类似于生产环境的环境,无需在本地安装任何内容。最好使用不同的流程来在开发分支中运行测试,然后构建一个没有开发/测试依赖关系的用于生产/暂存的镜像。 - belgoros
我以前做过这个流程 - 它需要使用不同的docker-compose文件,这样“测试”环境在运行期间可以构建和填充自己的数据库,而不是依赖于现有的数据库。 这是完全可行的。 当然,有您提到的限制,但同时,特别是当我运行集成测试时,我更喜欢测试针对一个更好地模拟我的生产环境而不是我的开发环境的应用环境运行,尤其是如果我在生产中使用Docker。 - streetlogics
3个回答

9

尝试

docker-compose run -e "RAILS_ENV=test" api bundle exec rspec spec/link/to/file.rb

2

在运行任何Docker命令之前,您应该在主机上运行bundle exec rspec

# 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 ... ...

您可以设置一个带有一些依赖项的部分 Docker Compose 环境,这对于在运行测试之前启动它们很有用。

docker-compose up -d mysql redis
# Change config/settings.yml and config/database.yml to point at localhost
bundle exec rails rspec

在Docker中运行测试会遇到两个实际问题。

  1. 如果您尝试在Dockerfile中运行测试,则无法访问在同一docker-compose.yml文件中定义的任何其他服务。特别是在使用Active Record的情况下,应用程序实际上无法启动,甚至无法运行单元测试,除非数据库可用。因此,您无法真正在Dockerfile中运行测试。

  2. 如果您尝试在应用程序启动时运行测试,则需要在Docker镜像中包含所有测试依赖项(这会增加镜像大小和潜在的安全攻击面)。您需要决定是否始终要运行测试(这会增加启动时间,可能显著),还是只在某些时候运行它们(这在普通的Docker Compose设置中很麻烦,但在更强大的CI系统中相当简单)。


我更新了注释,你可以看到我正在使用 wait-for-it 脚本来检查数据库是否可用。 - belgoros
谢谢您的回复,它证实了我有关在Docker镜像中集成开发和测试环境的需求的想法 - 这太长了。 - belgoros

1

我发现这对我有用:

# 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"]

现在运行测试:

docker-compose run test ./specs/path/to/your/test_spec.rb

希望这能对某人有所帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接