Railtie 및 Generator의 Spec 테스트

10673 단어 RubyRails
지아이허브공개rack-dev-mark에는 얼마 전 레일티와 제너레이터가 추가됐지만, 스펙 테스트를 쓰지 못해 미묘하다는 생각이 들었다.

Spec 시험을 못 본 이유.


Rails는 initialize를 여러 번 사용할 수 없습니다.


Rails3.2에서 Rails::Application이 두 개 이상의 하위 클래스를 상속하면 오류가 발생합니다.
app = Class.new(::Rails::Application)
app = Class.new(::Rails::Application)
> RuntimeError: You cannot have more than one Rails::Application
여러 번 불러서는 안 된다initialize!.
app = Class.new(::Rails::Application)
app.initialize!
app.initialize!
> RuntimeError: Application has been already initialized.
Rails4에서는 이 문제가 발생하지 않았지만 3.2를 테스트 대상에서 삭제하기에는 너무 이르다.

공략 방법


그리고 오랜 고민 끝에 공략했다.

rspec 내에서 fork


포크 과정에서 테스트를 진행하면 인티리얼즈 레일즈에서 가능합니다.
이때 반드시 고려해야 할 것은 다음과 같은 두 가지이다
  • Coverage 통합
  • 테스트 결과의sync
  • Coverage 통합

    Coveralls원래는 각 루비와gem의 Coverage를 합친 것으로 포크라도 합칠 수 있었다.
    로컬에서 단순cov를 사용하는 경우 프로세스 간에 서로 커버된 결과를 덮어쓰기 때문에 결과가 올바르지 않습니다.
    스펙 테스트에 다음과 같은 내용을 써서 해결합니다.
    spec/spec_helper.rb
    resultset_path = SimpleCov::ResultMerger.resultset_path
    FileUtils.rm resultset_path if File.exists? resultset_path
    
    SimpleCov.use_merging true
    SimpleCov.at_exit do
      SimpleCov.command_name "fork-#{$$}"
      SimpleCov.result.format!
    end
    
    우선SimpleCov.use_merging true, 이것은 이전에 실행된coverage의 결과를 합병하는 설정이다.
    합병cucumber테스트와rspec테스트 등에 사용됩니다.
    단, rspec의 프로세스 fork가 되면, 이렇게 병합된 키도 같기 때문에 덮어씁니다.
    따라서 비결은 SimpleCovat_exit를 고리로 합치기 전에 버튼을 바꾸는 것이다.
    SimpleCov.at_exit do
      SimpleCov.command_name "fork-#{$$}"
      SimpleCov.result.format!
    end
    
    그리고 이렇게 되면 과거의 테스트도 합병되어 시작할 때 초기화된다.
    resultset_path = SimpleCov::ResultMerger.resultset_path
    FileUtils.rm resultset_path if File.exists? resultset_path
    
    이렇게 하면 포크의 rspec의 Coverage를 순조롭게 합병할 수 있습니다!

    테스트 결과의 sync


    rspec 코드를 상당히 읽었어요.
    spec/support/fork_helper.rb
    shared_context 'forked spec' do
      around do |example|
        read, write = IO.pipe
        pid = fork do
          $stdout.sync = true
          $stderr.sync = true
          res = example.run
          Marshal.dump(res, write)
          write.close
        end 
        Process.waitpid2 pid 
        res = Marshal.load(read)
        example.example.send :set_exception, res if res && !res.empty?
        read.close
      end 
    end
    
    spec/rack/dev-mark/railtie_spec.rb
    require 'spec_helper'
    
    describe Rack::DevMark::Railtie do
      include_context 'forked spec'
    
      before do
        @app = Class.new(::Rails::Application)
        @app.config.active_support.deprecation = :stderr
        @app.config.eager_load = false
      end 
      context "rack_dev_mark enable" do
        before do
          @app.config.rack_dev_mark.enable = true
          @app.initialize!
        end 
        it 'inserts the middleware' do
          expect(@app.middleware.middlewares).to include(Rack::DevMark::Middleware)
        end 
      end
    end
    
    이런 느낌의 코드로 돌파했다.
    프로세스는 fork의 프로세스와 파이프를 교환하여 테스트 결과를 파이프로 부모 프로세스에 보내는 테스트 결과입니다.
    그리고 포크 프로세스의 결과를 포크의 결과로 처리하는 데 성공했다.

    그다음에 풀록!

    Rails4 이상을 지원하면 여러 앱을 제작할 수 있고, 레일티와 generator의 테스트도 간단하다.

    좋은 웹페이지 즐겨찾기