- 불안정한 테스트
- 느린 테스트
건강하지 않은 테스트
불안정한 테스트
불안정한 테스트란 무엇인가요?
가끔 실패하는 테스트이지만 충분히 여러 번 재시도하면 결국 통과하는 테스트입니다.
테스트가 불안정한 원인은 무엇인가요?
상태 누수
레이블: flaky-test::state leak
설명: 데이터 상태가 이전 테스트에서 유출되었습니다. 실제 원인은 아마도 여기서 불안정한 테스트가 아닙니다.
재현 난이도: 보통입니다. 일반적으로 동일한 스펙 파일을 실행하여 실패하는 스펙을 재현합니다.
해결 방법: 이전 테스트 및/또는 테스트 데이터 또는 환경이 수정된 위치를 수정하여 각 테스트 이후에 pristine 상태로 재설정되도록 합니다.
예시:
-
예시 1:
let_it_be
로 생성된 데이터 레코드가 테스트 예제 사이에서 공유되는 동안 일부 테스트가 의도적이든, 의도치 않게든 모델을 수정하여 테스트 예제에서 데이터가 동기화되지 않게 됩니다. 결과적으로 후속 테스트 예제나 재시도에서PG::QueryCanceled: ERROR
가 발생할 수 있습니다. 상태 누수와 해결 방법에 대한 자세한 내용은 GitLab 테스트 가이드를 참조하세요. - 예시 2: 마이그레이션 테스트가 데이터베이스를 롤백하고, 테스트를 수행한 뒤에 데이터베이스를 일관성 없는 상태로 롤백하여, 다음 테스트가 특정 열에 대해 알지 못하게 될 수 있습니다.
- 예시 3: 테스트가 후속 테스트에서 사용하는 데이터를 수정합니다.
- 예시 4: 데이터베이스 쿼리에 대한 테스트는 깨끗한 데이터베이스에서 통과하지만, 데이터베이스가 이전 테스트 시퀀스를 처리하기 위해 사용되는 CI/CD 파이프라인에서는 테스트가 실패합니다. 이는 쿼리 자체를 비정상적인 데이터베이스에서 작동하도록 업데이트해야 함을 의미합니다.
- 예시 5: 비관련 데이터베이스 연결이 비동기 요청에서 체크돼서, 테스트가 이러한 관련 없는 데이터베이스 연결을 실수로 사용합니다. 이 문제는 merge request에서 해결되었습니다.
- 예시 6: 데이터베이스 연결의 최대 생존 시간으로 인해 연결이 끊겨, 이에 따라 이러한 연결에 의존하는 트랜잭션이 실패합니다. 이 문제는 merge request에서 해결되었습니다.
- 예시 7: 테스트에 사용된 TCP 소켓이 다음 테스트 전에 닫히지 않았습니다. 이는 다른 TCP 소켓이 동일한 포트를 사용한 다음에 사용되어 트랜잭션 문제를 야기합니다.
데이터셋별
레이블: flaky-test::dataset-specific
설명: 테스트가 데이터셋이 특정(보통 제한된) 상태 또는 순서에 있다고 가정합니다. 테스트가 테스트 스위트를 실행하는 동안에는 이러한 가정이 사실이 아닐 수 있습니다.
재현 난이도: 중간입니다. 이 문제를 재현하기 위해 필요한 데이터 양이 로컬에서 얻기 어렵습니다. 순서 문제는 테스트를 반복적으로 여러 번 실행하여 쉽게 재현할 수 있습니다.
해결 방법:
- 데이터셋이 특정 상태에 있다고 가정하는 대신 테스트를 수정하여 ID를 하드코딩하지 않도록 합니다.
- 테스트가 순서에 신경 쓰지 않고 요소에 대해서만 신경 써야 한다면 단언을 완화합니다.
- 결정적인 순서를 지정하여 테스트를 수정합니다.
- 앱 코드를 결정적인 순서로 지정하여 테스트를 수정합니다.
예시:
-
예시 1: 테이블이 500개 이상의 열을 갖는 경우 데이터베이스가 다시 생성됩니다. 이 테스트는 머지 요청에서 통과할 수 있지만, 테스트 순서가 바뀌면 나중에
master
에서 실패할 수 있습니다. -
예시 2: 테스트는 존재하지 않는 ID로 레코드를 찾을 시 오류 메시지가 표시된다고 주장합니다. 이 테스트는 존재하지 않아야 하는 하드코딩된 ID(예:
42
)를 사용합니다. 이 테스트가 테스트 스위트의 초기에 실행되면 충분한 레코드가 생성되지 않으므로 통과할 수 있지만, 스위트의 나중에 실행되는 즉시 ID가 실제로42
인 레코드가 있을 수 있으므로 테스트가 실패할 수 있습니다. -
예시 3:
ORDER BY
를 지정하지 않으면 데이터베이스에 결정적인 순서가 지정되지 않거나 테스트에서 데이터 레이스가 발생할 수 있습니다. - 예시 4.
너무 많은 SQL 쿼리
레이블: flaky-test::too-many-sql-queries
설명: SQL 쿼리 한도에 도달하여 Gitlab::QueryLimiting::Transaction::ThresholdExceededError
가 트리거됩니다.
재현 난이도: 중간입니다. 이 실패는 쿼리 캐시의 상태에 따라 달려있으며 이는 스펙의 순서에 영향을 받을 수 있습니다.
해결 방법: 쿼리 횟수 제한 문서를 참조하세요.
랜덤 입력
레이블: flaky-test::random input
설명: 테스트는 가끔 기대와 일치하는 랜덤 값을 사용하거나 그렇지 않을 수 있습니다.
재현 난이도: 쉽습니다. 문제가 재현되면 테스트를 로컬에서 수정하여 해당 “랜덤 값”을 사용할 수 있습니다.
해결 방법: 문제가 재현되면 테스트 또는 앱을 쉽게 디버그하고 수정할 수 있어야 합니다.
예시:
- 예시 1: 데이터 입력이 무작위로 발생하기 때문에 가끔만 나타나는 특정 데이터를 처리하는 테스트가 충분히 강력하지 않습니다.
불안정한 DOM 선택기
Label: flaky-test::unreliable dom selector
Description: 테스트에 사용된 DOM 선택기가 불안정합니다.
Difficulty to reproduce: 중간부터 어려움. DOM 선택기가 중복되는지, 지연 후 나타나는지 등에 따라 다름. API나 컨트롤러에 지연을 추가하면 이슈를 재현하기 쉬워질 수 있습니다.
Resolution: 이 문제에 따라 다르지만, 종종 요청이 완료될 때까지 기다리거나 페이지를 아래로 스크롤하는 것이 해결책이 될 수 있습니다.
Examples:
-
Example 1: 고유하지 않은 CSS 선택기가 한 개 이상의 요소와 매치되거나, 렌더링 시간을 허용하지 않는 기다리지 않는 선택기 방법으로 인해
element not found
오류가 발생하는 경우. - Example 2: CSS 선택기가 GraphQL 요청이 완료된 후에 나타나며 UI가 업데이트된 경우.
- Example 3: false-positive 테스트, Capybara는 페이지 방문 후 즉시 true를 반환하고 페이지가 완전히 로드되지 않은 경우, 또는 웹 드라이버가 감지할 수 없는 경우(뷰포트 외부에 렌더링되거나 다른 요소 뒤에 렌더링되는 경우)입니다.
날짜 및 시간에 민감한
Label: flaky-test::datetime-sensitive
Description: 테스트는 특정 날짜나 시간을 가정합니다.
Difficulty to reproduce: 쉽게 중간부터 어려움. 테스트가 특정 날짜 이후에 일관되게 실패하는지, 또는 특정 시간이나 날짜에만 실패하는지에 따라 다름.
Resolution: 시간을 고정하는 것이 일반적으로 좋은 해결책입니다.
Examples:
불안정한 인프라
Label: flaky-test::unstable infrastructure
Description: CI 인프라 문제로 테스트가 가끔 실패합니다.
Difficulty to reproduce: 어려움. CI 인프라 문제를 재현하기가 정말 어렵습니다. 로컬에서 컨테이너를 사용함으로써 가능할 수 있습니다.
Resolution: 전용 이슈에서 인프라 부서와 대화를 시작하는 것이 보통 좋은 아이디어입니다.
Examples:
어떻게 로컬에서 불안정한 테스트를 재현할까요?
- 로컬에서 실패를 재현하세요
- CI 작업 로그에서 RSpec
seed
를 찾으세요 - 또는
while :; do bin/rspec <spec> || break; done
을 반복해서 실행하여seed
를 찾으세요
- CI 작업 로그에서 RSpec
-
bin/rspec --seed <이전에 찾은>
및bin/rspec --seed <이전에 찾은> --bisect <spec>
로 실패하는 예제를 줄이세요. - 남아 있는 예제를 확인하고 상태 누출을 주의하세요
- 예)
let_it_be
로 생성된 레코드를 업데이트하는 것이 문제의 일반적인 원인입니다.
- 예)
- 수정 후,
seed
로 테스트를 다시 실행하세요 - 스펙이 무작위 순서로 실행될 수 있는지 확인하기 위해
scripts/rspec_check_order_dependence
를 실행하세요 - 다시
while :; do bin/rspec <spec> || break; done
을 반복해서 실행하세요 (간식을 가져가며) 원래대로 불안정하지 않음을 확인하세요
격리된 테스트
master
브랜치에서 불안정한 테스트가 발견되면:
- 해당 그룹 라벨을 포함한 ~"failure::flaky-test" 이슈를 생성하세요.
- 첫 번째 실패 후 테스트를 격리하세요. 테스트가 적시에 수정되지 않을 경우 개발자 모두의 생산성에 영향을 미치므로 격리되어야 합니다.
RSpec
빠른 격리
테스트를 매우 빨리 비활성화해야 하는 경우(10분 미만), 대신 ~pipeline::expedited
라벨을 사용하는 것을 고려하세요.
파이프라인을 열고 파이프라인을 기다리지 않아도 빠르게 테스트를 격리하려면 빠른 격리 프로세스를 따를 수 있습니다.
빠른 격리 후 무슨 일이 일어나고 있는지 확인하기 위해 장기 격리 MR을 항상 열어주세요! 빠른 격리 프로젝트의 테스트는 빠른 격리 프로젝트의 컨텍스트에서 실행되지 않기 때문입니다.
장기 격리
테스트를 빠르게 격리한 후, 장기 격리 프로세스를 진행하실 수 있습니다. 이 과정은 MR을 열어 진행할 수 있습니다.
먼저, 올바른 테스트 파일에 feature_category
메타데이터가 있는지 확인하세요. 이는 테스트 파일의 올바른 속성을 보장하기 위함입니다.
그 후, 이전에 만든 ~"failure::flaky-test" 이슈의 URL을 사용하여 quarantine: '<issue url>'
메타데이터를 추가할 수 있습니다.
# 단일 스펙을 격리하세요
it '성공함', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345' do
expect(response).to have_gitlab_http_status(:ok)
end
# describe/context 블록도 격리하세요
describe '#flaky-method', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345' do
[...]
end
이렇게 하면 CI에서 건너뛸 것입니다. 기본적으로 격리된 테스트는 로컬에서 실행됩니다.
로컬 개발에서도 --tag ~quarantine
로 실행하여 이를 건너 뛸 수 있도록 해주세요:
# Bash
bin/rspec --tag ~quarantine
# ZSH
bin/rspec --tag \~quarantine
또한, 확인해주세요:
- MR에 ~"quarantine" 라벨이 있는지
- MR 설명에 표준 용어로 링크된 MR에 대해 언급되었는지
공유된 예제/컨텍스트를 격리해서는 안되며, it_behaves_like
나 include_examples
를 격리할 수 없습니다:
# Rubocop에서 플래그 처리될 것입니다
shared_examples 'loads all the users when opened', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345' do
[...]
end
# 동작하지 않음
it_behaves_like 'a shared example', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345'
# 동작하지 않음
include_examples 'a shared example', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345'
장기 격리 MR이 프로덕션에 도달한 후, 이전에 만든 빠른 격리 MR을 되돌려야 합니다.
기능 카테고리별 격리된 테스트 찾기
특정 기능 카테고리에 대한 모든 격리된 테스트를 찾으려면 ripgrep
를 사용하세요:
rg -l --multiline -w "(?s)feature_category:\s+:global_search.+quarantine:"
Jest
Jest 스펙의 경우, .skip
메서드와 eslint-disable-next-line
주석을 사용하여 jest/no-disabled-tests
ESLint 규칙을 비활성화하고 이슈 URL을 포함할 수 있습니다. 다음은 예시입니다:
// quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/56789
// eslint-disable-next-line jest/no-disabled-tests
it.skip('should throw an error', () => {
expect(response).toThrowError(expected_error)
});
이는 --runInBand
Jest 명령줄 옵션으로 테스트 스위트가 실행될 때에만 스킵됩니다:
jest --runInBand
격리된 스펙이 포함된 파일 목록은 다음 명령어로 찾을 수 있습니다:
yarn jest:quarantine
두 테스트 프레임워크 모두 ~"quarantined test"
라벨을 이슈에 추가해야합니다.
테스트가 격리된 후에는 3가지 선택지가 있습니다:
- 테스트 수정(즉, 방해요소를 제거하다).
- 테스트를 더 낮은 수준의 테스트로 이동.
- 테스트를 완전히 제거(예: 이미 더 낮은 수준의 테스트가 있거나, 다른 동일 수준의 테스트를 중복하거나, 너무 많은 것을 테스트하는 등).
자동 재시도 및 방해요소 테스트 검출
저희 CI에서는 실패하는 예제를 몇 번 자동으로 재시도하기 위해 RSpec::Retry
를 사용합니다.
정확한 재시도 횟수는 spec/spec_helper.rb
에서 확인할 수 있습니다.
또한 사용자 정의 Gitlab::RspecFlaky::Listener
를 사용합니다.
이 리스너는 master
브랜치의 maintenance
예약된 파이프라인의 update-tests-metadata
작업에서 실행되어, 오류가 발생한 예제를 rspec/flaky/report-suite.json
에 저장합니다.
그런 다음, 이 보고서 파일은 모든 파이프라인의 retrieve-tests-metadata
작업에 의해 검색됩니다.
원래 구현된 내용은 다음과 같습니다: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13021.
로컬에서 재시도를 활성화하려면 RETRIES
환경 변수를 사용할 수 있습니다.
예를 들어 RETRIES=1 bin/rspec ...
는 실패한 예제를 한 번 재시도합니다.
로컬에서 보고서를 생성하려면 FLAKY_RSPEC_GENERATE_REPORT
환경 변수를 사용하세요.
예를 들어, FLAKY_RSPEC_GENERATE_REPORT=1 bin/rspec ...
입니다.
rspec/flaky/report-suite.json
보고서의 사용
rspec/flaky/report-suite.json
보고서는 매일 한 번 Snowflake에 가져오기되어 내부 대시보드와 모니터링됩니다.
GitLab에서 겪은 문제들
-
rspec-retry
가 일부 API 스펙이 실패할 때 문제를 일으키고 있음: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9825 -
PG::UniqueViolation
으로 인한 가끔씩 실패하는 RSpec 문제: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9846 - ffaker가 테스트가 처리할 수 없는 이상한 데이터를 생성함 (그리고 테스트는 예측 가능해야하므로 이는 좋지 않음):
-
spec/mailers/notify_spec.rb
를 보다 견고하게 만들기: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10015 -
spec/requests/api/commits_spec.rb
에서 일시적인 실패: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9944 - ffaker 팩토리 데이터를 시퀀스로 대체하기: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10184
-
spec/finders/issues_finder_spec.rb
에서 일시적인 실패: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10404
-
순서 의존적인 방해요소 테스트
이러한 방해요소 테스트는 다른 테스트와 실행 순서에 따라 실패할 수 있습니다:
이러한 실패를 일으키는 테스트를 확인하려면 scripts/rspec_bisect_flaky
를 사용하여 실패를 재현하는 최소한의 테스트 조합을 얻을 수 있습니다:
- 먼저 실패한 테스트 이전에 실행된 스펙 목록을 가져옵니다. CI 작업 출력 로그에서
Knapsack node specs:
아래의 목록을 찾을 수 있습니다. -
스펙 목록을 파일로 저장한 다음 다음을 실행합니다:
cat knapsack_specs.txt | xargs scripts/rspec_bisect_flaky
순서 의존성 문제가 있는 경우 위의 스크립트에서 실패를 최소화한 재현이 출력됩니다.
시간이 중요한 불안정한 테스트
- https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10046
- https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10306
배열 순서 예상
기능 테스트
- 연습을 시작하기 전에 테스트가 필요로 하는 모든 데이터를 생성해야 합니다: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12059
- Bis: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12604
- Bis: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12664
- 페이지의 내용이 아닌 기본 데이터베이스 상태에 대해 단언하십시오: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10934
- JS 테스트에서 요소를 이동할 때 Capybara가 정확히 클릭하려는 때 요소가 이동하여 Capybara가 잘못 클릭할 수 있음
- 이벤트 핸들러가 설정되기 전에 JS 이벤트를 트리거합니다
- 마크다운 이미지의
src
속성을 단언할 때 이미지가 게을러로드될 때까지 기다리십시오 - 플래시 알림 배너에 대해 단언을 피하십시오
Capybara 뷰포트 크기 관련 문제
- spec/features/issues/filtered_search/filter_issues_spec.rb의 일시적 실패: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10411
Capybara JS 드라이버 관련 문제
- AJAX 요청이 없을 때 AJAX를 기다리지 마십시오: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10454
- Bis: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12626
Capybara 기대시간 만료
매달린 사양
만약 특정 사양이 매달리거나 CI에서 시간 초과되면, 이는 Rails의 LoadInterlockAwareMonitor 데드락 버그의 결과일 수 있습니다.
진단을 위해 다음을 사용할 수 있습니다. sigdump 루비 스레드 덤프를 출력하려면:
- 로컬에서 매달리는 사양을 실행합니다.
-
다음 명령을 실행하여 루비 스레드 덤프를 트리거합니다:
kill -CONT <pid>
- 스레드 덤프는
/tmp/sigdump-<pid>.log
파일에 저장됩니다.
만약 load_interlock_aware_monitor.rb
과 관련된 라인을 보게된다면, 이것은 관련이 있을 가능성이 높습니다:
/builds/gitlab-org/gitlab/vendor/ruby/3.2.0/gems/activesupport-7.0.8.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:17:in `mon_enter'
/builds/gitlab-org/gitlab/vendor/ruby/3.2.0/gems/activesupport-7.0.8.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:22:in `block in synchronize'
/builds/gitlab-org/gitlab/vendor/ruby/3.2.0/gems/activesupport-7.0.8.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/builds/gitlab-org/gitlab/vendor/ruby/3.2.0/gems/activesupport-7.0.8.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
공장을 만들기 전에 작업한 예제를 확인하세요:
- https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81112
- https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158890
- https://gitlab.com/gitlab-org/gitlab/-/issues/337039
제안
테스트 파일 분리
큰 RSpec 파일을 여러 파일로 분리하여 컨텍스트를 좁히고 문제가 되는 테스트를 식별하는 데 도움이 될 수 있습니다.
CI에서 작업 실패 재현하기
CI에서 작업 실패를 복제하는 것은 테스트가 어떻게 실패하는지, 그 이유를 찾는 데 항상 도움이 됩니다. 이를 위해 동일한 테스트 파일을 동일한 스펙 순서로 실행하도록 작업을 강제하는 것이 필요합니다. 병렬화된 작업에 테스트를 분산하는 Knapsack을 사용하기 때문에 파일이 두 개의 파이프라인 사이에서 다르게 분산될 수 있으므로 이 작업 분배를 직접 지정할 필요가 있습니다.
- 재현하고 싶은 작업을 찾아 해당 작업이 실행된 커밋을 식별하고, 동일한 프로젝트 사본을 실행하는 것을 확실하기 위해 로컬
gitlab-org/gitlab
브랜치를 동일한 커밋으로 설정합니다. - 작업 로그에서 Knapsack에 의해 분산된 테스트 파일 목록을 찾습니다.
bundle exec rspec
를 검색하면, 이 명령의 마지막 인수에 파일 이름 목록이 포함되어 있어야 합니다. 이 목록을 복사합니다. - 테스트 파일 분배가 발생하는
tooling/lib/tooling/parallel_rspec_runner.rb
로 이동합니다. 이 MR를 참고해보세요. 단계 2에서 복사한 파일 목록을TEST_FILES
상수에 저장하고, 예제 MR에서 수행한 것처럼 RSpec가 이 목록을 실행하도록rspec_command
메소드를 업데이트합니다. - 아래의 단계를 참조하여
spec/tooling/lib/tooling/parallel_rspec_runner_spec.rb
의 테스트를 건너뛰어서 파이프라인이 이른 시기에 실패하지 않도록 합니다. - 특정 버전에 대해 파이프라인이 실행되도록 하고자 하기 때문에 병합된 결과 파이프라인을 실행하지 않고 싶을 것입니다. 이를 달성하려면 MR에 병합 충돌을 도입할 수 있습니다.
- 테스트 순서를 유지하기 위해, 원래 실패한 작업에서 표시된 값으로
spec/support/rspec_order.rb
파일을 업데이트합니다. 여기에서 보여진 대로Kernel.srand
값을 하드코딩합니다. 이 값을Randomized with seed
로 검색하여 확인할 수 있습니다. 중요: 불편을 드려 정말 죄송합니다만, 저는 온라인 상태가 아니라서 언제든지 추가 도움을 드릴 수 없습니다.
자원
- Flaky Tests: Are You Sure You Want to Rerun Them?
- Flaky Tests를 처리하고 제거하는 방법
- 루비 온 레일즈 테스트 스위트의 불안정성 다루는 팁
- ‘Flaky’ tests: a short story
- 테스트 인사이트
느린 테스트
최상위 느린 테스트
우리는 rspec_profiling_stats
프로젝트에서 테스트 소요 시간에 대한 정보를 수집합니다. 이 데이터는 이 UI에서 GitLab Pages를 사용하여 표시됩니다.
이 이슈에서는 가이드로 작용할 수 있는 테스트 소요 시간의 임계값을 정의했습니다.
임계값을 초과하는 테스트에 대해서는 해당 그룹이 개선할 수 있도록 테스트 이슈에 느림 현상을 자동으로 보고합니다.
합법적인 이유로 느린 테스트에 대해 이슈 생성을 건너뛰려면 allowed_to_be_slow: true
를 추가하십시오.
날짜 | 피처 테스트 | 컨트롤러 및 요청 테스트 | 유닛 | 기타 | 메소드 |
---|---|---|---|---|---|
2023-02-15 | 67.42 초 | 44.66 초 | - | 76.86 초 | 최상위 느린 테스트 최대 제거 |
2023-06-15 | 50.13 초 | 19.20 초 | 27.12 | 45.40 초 | 최상위 100개 느린 테스트 평균 |