PCCR - 완벽한 코드 커버리지 보고

21841 단어

Cover photo by Jonathan Cooper




프로젝트에 완벽한 코드 커버리지가 있고 아무도, 심지어 당신도 그것에 대해 모른다면 비둘기가 울까요?

완벽을 달성할 수는 없지만 범위를 제한하면 달성할 수 있습니다. ;)

완벽한 코드 커버리지는 분기를 포함하여 100%를 의미합니다. 참고: 코드에 분기가 없을 때 가장 쉽게 달성할 수 있습니다!

완벽한 코드 커버리지 보고는 모든 사람에게 이에 대해 알리고, 배지를 달고, PR에 댓글을 남기는 것입니다.

거기에 어떻게 가나요?




나는 최근에 유니코드gem 문자 집합과 일치하는 표준 정규식을 제공하는 Gitmoji(예: Ruby 라이브러리)을 작성했습니다.

분기문이 없는 간단한 라이브러리는 완벽하게 커버리지를 얻기는 쉬웠지만 보고 완벽함을 얻기에는 약간 복잡했습니다...

내 예제에서는 내가 선택한 언어로 Ruby를 사용하지만 이것의 대부분, 특히 Github Actions Coverage Workflow는 모든 언어에 적용됩니다.


이익



README.md



오픈 소스 프로젝트에서 자기 홍보는 중요합니다.

README.md에는 이제 영광스러운 배지가 있습니다.



풀 리퀘스트 자동화



또한 프로젝트에 대한 PR은 CodeCoverageSummary Github Action에서 아래와 같은 주석을 받아야 합니다.




패키지
회선 속도
건강


gitmoji 정규식
100%


요약

100% (50/50)




도구



  • CodeClimate SAAS

  • CodeCov SAAS

  • Coveralls SAAS

  • irongut/CodeCoverageSummary Github 작업

  • amancevice/setup-code-climate Github 작업

  • Coverage-related Gems 내가 사용하는 것:
  • gem "codecov", "~> 0.6" - 참고: codecov/codecov-action Github Action은 Ruby를 사용하지 않는 사람들을 위한 대안입니다. 예시를 남겼습니다in the coverage workflow
  • gem "simplecov", "~> 0.21", require: false
  • gem "simplecov-cobertura" Jenkins 또는 기타 도구에 대한 XML 형식 제공
  • gem 'simplecov-json' CodeClimate용 JSON 형식 제공
  • gem "simplecov-lcov", "~> 0.8", require: false lcov 형식 제공




  • 구현



    커버리지 워크플로우



    이것은 모든 것을 하나로 묶는 고기와 감자입니다!

    name: Code Coverage
    
    env:
      CI_CODECOV: true
      COVER_ALL: true
    
    on:
      push:
        branches:
          - 'main'
          - '*-maintenance'
          - '*-dev'
          - '*-stable'
        tags:
          - '!*' # Do not execute on tags
      pull_request:
        branches:
          - '*'
      # Allow manually triggering the workflow.
      workflow_dispatch:
    
    # Cancels all previous workflow runs for the same branch that have not yet completed.
    concurrency:
      # The concurrency group contains the workflow name and the branch name.
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: true
    
    jobs:
      test:
        name: Specs with Coverage - Ruby ${{ matrix.ruby }} ${{ matrix.name_extra || '' }}
        if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')"
        strategy:
          fail-fast: false
          matrix:
            experimental: [false]
            rubygems:
              - latest
            bundler:
              - latest
            ruby:
              - "2.7"
    
        runs-on: ubuntu-latest
        continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }}
        steps:
          - uses: amancevice/setup-code-climate@v0
            name: CodeClimate Install
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            with:
              cc_test_reporter_id: ${{ secrets.CC_TEST_REPORTER_ID }}
    
          - name: Checkout
            uses: actions/checkout@v3
    
          - name: Setup Ruby & Bundle
            uses: ruby/setup-ruby@v1
            with:
              ruby-version: ${{ matrix.ruby }}
              rubygems: ${{ matrix.rubygems }}
              bundler: ${{ matrix.bundler }}
              bundler-cache: true
    
          - name: CodeClimate Pre-build Notification
            run: cc-test-reporter before-build
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Run tests
            run: bundle exec rake test
    
          - name: CodeClimate Post-build Notification
            run: cc-test-reporter after-build
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Code Coverage Summary Report
            uses: irongut/[email protected]
            with:
              filename: ./coverage/coverage.xml
              badge: true
              fail_below_min: true
              format: markdown
              hide_branch_rate: true
              hide_complexity: true
              indicators: true
              output: both
              thresholds: '95 97'
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Add Coverage PR Comment
            uses: marocchino/sticky-pull-request-comment@v2
            if: matrix.ruby == '2.7' && always()
            with:
              recreate: true
              path: code-coverage-results.md
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Coveralls
            uses: coverallsapp/github-action@master
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            with:
              github-token: ${{ secrets.GITHUB_TOKEN }}
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
    #      Using the codecov gem instead.
    #      - name: CodeCov
    #        uses: codecov/codecov-action@v2
    #        if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
    #        with:
    #          files: ./coverage/coverage.xml
    #          flags: unittests
    #          name: codecov-upload
    #          fail_ci_if_error: true
    #        continue-on-error: ${{ matrix.experimental != 'false' }}
    


    심플코브



    상수 참고: 일부 상수는 아래에서 사용됩니다. RUN_COVERAGEALL_FORMATTERSspec/spec_helper.rb 구성이 로드되기 전에 실행되는 .simplecov 에 설정됩니다. 기타, 예. RUBY_ENGINE , RUBY_VERSION 은 표준 Ruby입니다.

    적용 범위를 확인하려면 코드를 로드하기 전에 require "simplecov" 해야 합니다.

    if RUN_COVERAGE
      require "simplecov" # Config file `.simplecov` is run immediately when simplecov loads
      require "codecov"
      require "simplecov-json"
      require "simplecov-lcov"
      require "simplecov-cobertura"
      # This will override any formatter set in .simplecov
      if ALL_FORMATTERS
        SimpleCov::Formatter::LcovFormatter.config do |c|
          c.report_with_single_file = true
          c.single_report_path = "coverage/lcov.info"
        end
    
        SimpleCov.formatters = [
          SimpleCov::Formatter::HTMLFormatter,
          SimpleCov::Formatter::CoberturaFormatter,
          SimpleCov::Formatter::LcovFormatter,
          SimpleCov::Formatter::JSONFormatter, # For CodeClimate
          SimpleCov::Formatter::Codecov # For CodeCov
        ]
      end
    end
    
    


    아래와 같이 .simplecov 구성으로 구성합니다.

    # frozen_string_literal: true
    
    # To get coverage
    # On Local, default (HTML) output, it just works, coverage is turned on:
    #   bundle exec rspec spec
    # On Local, all output formats:
    #   COVER_ALL=true bundle exec rspec spec
    #
    # On CI, all output formats, the ENV variables CI is always set,
    #   and COVER_ALL, and CI_CODECOV, are set in the coverage.yml workflow only,
    #   so coverage only runs in that workflow, and outputs all formats.
    #
    
    if RUN_COVERAGE
      SimpleCov.start do
        enable_coverage :branch
        primary_coverage :branch
        add_filter "test"
        track_files "**/*.rb"
    
        if ALL_FORMATTERS
          command_name "#{ENV["GITHUB_WORKFLOW"]} Job #{ENV["GITHUB_RUN_ID"]}:#{ENV["GITHUB_RUN_NUMBER"]}"
        else
          formatter SimpleCov::Formatter::HTMLFormatter
        end
    
        minimum_coverage(100)
      end
    else
      puts "Not running coverage on #{RUBY_ENGINE} #{RUBY_VERSION}"
    end
    



    최종 결과



    Github Actions Run

    RSpec 대신 MiniTest를 사용하고 (아직) 100% 테스트 커버리지가 없는 oauth gem을 포함하여 다른 gem에서 이 패턴을 다시 구현했습니다. 대부분의 구현은 동일합니다.

    좋은 웹페이지 즐겨찾기