버전 제어 후크에서 단위 테스트를 실행하는 것이 좋습니까?


43

기술적 인 관점에서 특정 커밋을 원격 기본 브랜치에 병합하기 전에 단위 테스트를 실행하는 사전 / 사후 푸시 후크를 추가 할 수 있습니다.

내 질문은-빌드 파이프 라인에서 단위 테스트를 유지하는 것이 더 좋습니까 (따라서 깨진 커밋을 리포지토리에 도입) 또는 "나쁜"커밋이 발생하지 않도록하는 것이 좋습니다.

나는이 두 가지 옵션으로 제한되지 않는다는 것을 알고 있습니다. 예를 들어, 병합 커밋을 repo로 푸시하기 전에 모든 커밋을 분기하고 테스트 할 수 있습니다. 그러나이 두 가지 솔루션 중 하나를 선택해야하는 경우 어떤 솔루션을 선택해야하며 정확히 어떤 이유가 있습니까?


답변:


35

아니요, 두 가지 이유가 아닙니다.

속도

커밋은 빨라야합니다. 예를 들어, 500ms가 걸리는 커밋은 너무 느리고 개발자가 더 적게 커밋하도록 권장합니다. Hello World보다 큰 프로젝트에서는 수십 또는 수백 가지의 테스트가 수행되므로 사전 커밋 중에 테스트를 실행하는 데 너무 많은 시간이 걸립니다.

물론 분산 아키텍처에서 몇 분 또는 한 대의 컴퓨터에서 몇 주 또는 몇 달 동안 수천 번의 테스트를 수행하는 대규모 프로젝트의 경우 상황이 악화됩니다.

최악의 부분은 더 빨리 만들기 위해 할 수있는 일이 많지 않다는 것입니다. 백 단위 테스트를 수행하는 소규모 Python 프로젝트는 평균 서버에서 실행하는 데 최소 1 초가 걸리지 만 훨씬 더 오래 걸립니다. C # 응용 프로그램의 경우 컴파일 시간으로 인해 평균 4-5 초입니다.

이 시점에서 더 나은 서버에 대해 $ 10 000를 추가로 지불하면 시간이 많이 걸리지 않지만 여러 서버에서 테스트를 실행하면 속도가 느려집니다.

둘 다 수천 개의 테스트 (기능, 시스템 및 통합 테스트)가있을 때 비용이 많이 들기 때문에 몇 주가 아닌 몇 분만에 테스트를 실행할 수 있지만 소규모 프로젝트에는 도움이되지 않습니다.

대신에 할 수있는 일은 :

  • 커밋을 수행하기 전에 로컬에서 수정 한 코드와 관련된 테스트를 개발자가 실행하도록 권장하십시오. 수천 개의 단위 테스트를 실행할 수는 없지만 5-10 개를 실행할 수 있습니다.

    관련 테스트를 찾아서 실행하는 것이 실제로 쉽고 빠릅니다. 예를 들어 Visual Studio는 마지막 실행 이후에 수행 된 변경으로 인해 영향을받을 수있는 테스트를 감지 할 수 있습니다. 다른 IDE / 플랫폼 / 언어 / 프레임 워크도 비슷한 기능을 할 수 있습니다.

  • 커밋을 최대한 빨리 유지하십시오. 스타일 규칙을 적용하는 것이 좋습니다. 종종 유일한 방법이기 때문에 그러한 검사는 놀랍도록 빠르기 때문입니다. 정적 분석은 빠르게 진행 되 자마자 괜찮습니다. 단위 테스트 실행이 정상이 아닙니다.

  • Continuous Integration 서버에서 단위 테스트를 실행하십시오.

  • 개발자가 빌드를 중단했을 때 (또는 단위 테스트가 실패했을 때 자동으로 알려야합니다. 이는 컴파일러를 코드에 도입 할 수있는 가능한 실수 중 일부를 검사하는 도구로 간주하는 경우와 거의 같습니다).

    예를 들어, 마지막 빌드를 확인하기 위해 웹 페이지로 이동하는 것은 해결책이 아닙니다. 자동으로 알려야 합니다. 팝업 표시 또는 SMS 전송은 정보를받는 방법의 두 가지 예입니다.

  • 개발자가 빌드를 중단 (또는 회귀 테스트 실패)하는 것이 좋지 않다는 것을 이해하고, 그것이 발생하자마자 가장 우선 순위는 문제를 해결하는 것입니다. 상사가 내일 배송을 요청한 우선 순위가 높은 기능을 수행하고 있는지 여부는 중요하지 않습니다. 빌드를 실패하면 수정해야합니다.

보안

리포지토리를 호스팅하는 서버는 특히 보안상의 이유로 단위 테스트와 같은 사용자 지정 코드를 실행해서는 안됩니다. 이러한 이유는 동일한 GitLab 서버의 CI 러너에서 이미 설명 되었습니까?

반면, 사전 커밋 후크에서 빌드 서버의 프로세스를 시작하려는 경우 커밋 속도가 훨씬 느려집니다.


4
나는 이것이 빌드 서버를위한 것임을 동의합니다. 소스 제어는 응용 프로그램 작동을 보장하지 않고 소스 코드를 관리하기위한 것입니다.
Matthew

4
극단적 인 경우 빌드를 중단 할 때 보복 이 필요한 알림 도구 일 수 있습니다.

37
0.5 초가 너무 느려? 커밋되는 내용을 마지막으로 살펴본 다음 적절한 커밋 주석을 생각하고 입력하는 것과 비교하여 버킷이 줄었습니다.
Doval

5
@Doval : 차이점은 마지막으로 한 번 보거나 의견에 대해 생각할 때 사전 예방 적이므로 기다리지 않는다는 것입니다. IDE에서 마지막 문자를 입력하기 전에 소비 한 시간과 커밋이 완료된 후 다시 입력을 시작할 수있는 시간이 아니라 얼마나 기다려야 하는가입니다. 그렇기 때문에 컴파일러가 빨라야합니다. 코드를 읽고 쓰는 데 더 많은 시간을 소비하는 것은 중요하지 않습니다. 코드를 컴파일 할 때 대기하지 않고 코드를 컴파일 할 때 다른 활동으로 전환하려는 유혹을 받기 때문입니다.
Arseni Mourzenko

10
@ 토마스 : 산만 함이 아니라 성가심에 관한 것입니다. 같은 방식으로 100ms. 사람들이 웹 사이트를 사용하는 방식에 "측정 가능한 영향을 미칩니다" . 여기서 동일한 패턴 : 100ms YouTube 동영상을 보거나 PC를 시작하는 데 드는 시간과 비교하면 아무것도 아닙니다. 의식적으로 600ms의 차이를 느끼지 못할 것입니다. 그리고 700 ms. 지연. 그러나 무의식적으로 행동에 영향을 미칩니다. 같은 방식으로 커밋이 약간 느리면 일찍 커밋하지 않는 것이 좋습니다.
Arseni Mourzenko

41

동료 응답자와 동의하지 않는 사람이 되겠습니다.

이것은 TFS 세계에서 Gated Check-in으로 알려져 있으며 다른 곳에서도 기대합니다. 게이트 된 체크인으로 분기에 체크인을 시도하면, 선반 세트가 서버로 전송되어 변경 사항 빌드 및 지정된 (읽기 : 모두) 단위 테스트가 통과되도록합니다. 그들이하지 않으면, 당신이 빌드를 파산 한 나쁜 원숭이임을 알려줍니다. 그렇다면 변경 사항이 소스 제어로 변경됩니다 (예!).

필자의 경험에 따르면, 게이트 체크인은 성공적인 단위 테스트와 소프트웨어 품질의 가장 중요한 프로세스 중 하나입니다.

왜?

  • 게이트 된 체크인은 사람들이 깨진 테스트를 수정하도록 강요하기 때문입니다. 즉시 깨진 테스트 뭔가 사람들이됨에 따라 할 수 할 것이 아니라 있어야 할, 그들은 드 우선 순위가 될 게으른 엔지니어 및 / 또는 뻔뻔 비즈니스 사람들.
    • 테스트가 길어질수록 수정하기가 더 어렵고 비용이 많이 듭니다.
  • 사람들 테스트 실행 하지 않고 테스트를 실행 하자마자 , 게으른 / 잊어 버린 엔지니어 및 / 또는 뻔뻔스런 사업가들이 테스트 실행을 우회합니다.
  • 빨리 단위 테스트가 영향으로 시간을 커밋하기 때문에, 사람들은 정말 자신의 테스트 만들기에 대한 배려를 시작할 단위 테스트를. 속도가 중요합니다. 재현성이 중요합니다. 신뢰성이 중요합니다. 격리가 중요합니다.

물론 탑승 수속과 확실한 테스트 스위트를 제공 할 때마다 모든 변경 사항이 "안정적"이라는 이점이 있습니다. "마지막으로 빌드 한시기는 언제입니까?"라는 모든 오버 헤드 (및 오류 가능성)를 저장합니다. -모든 빌드는 개발하기에 충분합니다.

예, 테스트를 빌드하고 실행하는 데 시간이 걸립니다. 내 경험상 좋은 크기의 C # 앱과 ~ 5k 단위 테스트를 위해 5-10 분이 소요됩니다. 그리고 나는 그것에 관심이 없습니다. 예, 사람들은 자주 체크인해야합니다. 그러나 그들은 업무를 자주 업데이트하거나 이메일을 확인하거나 소프트웨어 엔지니어의 직업을 구성하는 커피 나 수십 가지의 다른 "코드를 작성하지 않은"작업을 수행해야합니다. 잘못된 코드를 체크 아웃하는 데 5-10 분이 소요됩니다.


3
+1 저는 많은 오픈 소스 프로젝트가 기여와 커밋을 명확하게 구분하고 있다고 덧붙이고 싶습니다. 게이트 된 체크인이 존재하는 이유와 매우 유사합니다.
JensG

게이트 체크인의 중요한 문제 중 하나는 어려운 코드의 공동 문제 해결을 방해한다는 것입니다. 이는 분산 된 팀에서 더욱 중요합니다.
CuriousRabbit

2
@CuriousRabbit-어떻게 생각하십니까? 사람들은 거의 투입하지 그들이 경우에도 공동 작업을 공동으로. 그렇지 않으면 선반 세트 또는 미완성 된 작업 지점이 나머지 팀을 방해하지 않으면서도 효과적입니다.
Telastyn

@ Telastyn– Shelvesets는 저에게 새로운 용어입니다. 나는 이것이 MS VS 옵션이며 많은 프로젝트에 대한 옵션이 아니라고 수집합니다. 모바일 앱 개발 분야에서 VS는 플레이어가 아닙니다.
CuriousRabbit

3
@CuriousRabbit-정말? 17 시간 이상 분산 된 팀은 공격자가 잠 들어있는 동안 빌드가 깨질 가능성보다 커밋을 기다리는 데 10 분을 더 신경 쓰는 데 더 관심이 있습니까? 그것은 ... 최적보다 적습니다.
Telastyn

40

커밋이 빠르게 실행됩니다. 일부 코드를 커밋하면 서버로 푸시되기를 원합니다. 테스트 배터리를 실행하는 동안 몇 분을 기다리지 않습니다. 나는 서버에 푸시하는 것에 대해 책임이 있으며 커밋 후크로 나를 돌보는 사람이 필요하지 않습니다.

즉, 일단 서버에 도착하면 즉시 분석하거나, 단위 테스트를 거쳐, 즉시 (또는 짧은 시간 내에) 구축해야합니다. 이것은 단위 테스트가 깨 졌거나 컴파일되지 않았거나 정적 분석 도구가 사용할 수있는 혼란을 주었다는 사실을 경고합니다. 이 작업이 더 빨리 이루어지면 (빌드 및 분석) 피드백이 더 빨라지고 더 빨리 해결할 수 있습니다 (생각은 두뇌에서 완전히 바뀌지 않았습니다).

따라서 클라이언트에 대한 커밋 후크에 테스트 등을 넣지 마십시오. 필요한 경우 사후 커밋 (CI 서버가 없기 때문에)하거나 CI 빌드 서버에 배치하고 코드 문제에 대해 적절하게 경고합니다. 그러나 커밋이 처음에 발생하는 것을 막지 마십시오.

또한 테스트 주도 개발 (Test Driven Development)에 대한 해석을 통해 먼저 부서진 단위 테스트를 확인 해야합니다 . 버그가 있음을 보여주고 문서화합니다. 그런 다음 나중에 체크인 하면 단위 테스트 를 수정 하는 코드가 됩니다. 단위 테스트가 통과 될 때까지 체크인을 방지하면 문제를 문서화하지 못한 단위 테스트에서 유효 확인 값이 줄어 듭니다.

관련 : 알려진 결함에 대한 단위 테스트가 있어야합니까? 그리고 실패한 단위 테스트에서 확인하는 가치는 무엇입니까?


2
Commits should run fast.이것의 장점은 무엇입니까? 현재 게이트 체크인을 사용하고 있기 때문에 궁금합니다. 보통 내 체크인은 한 시간 정도의 작업이 누적되므로 5 분 동안 기다리지 않아도됩니다. 사실 나는 경우는 일반적으로 시간을 것으로 나타났습니다 오전 (돌진의 결과로) 서두를 검증 빌드 바보 같은 실수를 잡기위한 가장 유용하다
저스틴

1
@Justin 5 분 대기는 어디에 있든지 5 분 대기하는 것입니다. 하나는 안된다 당신이 커밋 할 때마다 알긴 칼을 중단해야합니다. 그리고 한 시간 정도의 작업을 서로의 개념적 단위 인 여러 커밋으로 나누는 것이 드문 일이 아닙니다. (다른 커밋으로 CSS 조정은 말할 것도 없습니다). 이들 각각을 실행하는 데 5 분이 걸렸다면, 내 시간의 1/6이 테스트를 기다리는 데 소비됩니다. 이로 인해 버그를 추적하기 어려운 롤업 커밋이 커질 수 있습니다.

5 분 단위 테스트 실행을 기다 립니까? 작업중 인 프로젝트가 더 작은 구성 요소로 분류되어야한다고 생각합니다.
user441521

@ 저스틴 catching silly mistakes (as a result of rushing)정확히. 서두르는 것은 소프트웨어 엔지니어링에서 나쁜 습관입니다. Robert C. Martin은 수술과 같은 코드 작성을 권장합니다. youtube.com/watch?v=p0O1VVqRSK0
Jerry Joseph

10

원칙적으로, 사람들이 빌드를 망가 뜨리는 메인 라인을 변경하지 못하게하는 것이 합리적이라고 생각합니다. 즉, 리포지토리의 주요 지점을 변경하려면 모든 테스트가 여전히 통과해야합니다. 프로젝트의 모든 엔지니어가 다른 작업을 수행하는 데 시간을 잃는다는 점에서 빌드를 깨는 것은 너무 비용이 많이 듭니다.

그러나 커밋 후크의 특정 솔루션은 좋은 계획이 아닙니다.

  1. 개발자는 커밋하는 동안 테스트가 실행될 때까지 기다려야합니다. 개발자가 모든 테스트를 통과하기 위해 자신의 워크 스테이션을 기다려야하는 경우 귀중한 엔지니어 시간을 낭비한 것입니다. 테스트가 실패하여 엔지니어가 다시 전환해야하더라도 엔지니어는 다음 작업으로 넘어갈 수 있어야합니다.
  2. 개발자는 브랜치에서 깨진 코드를 커밋 할 수 있습니다. 더 큰 작업에서 개발자 버전의 코드는 통과 상태가 아닌 많은 시간을 소비 할 수 있습니다. 분명히 그 코드를 메인 라인에 병합하는 것은 매우 나쁠 것입니다. 그러나 개발자가 여전히 버전 관리를 사용하여 진행 상황을 추적 할 수 있다는 것이 중요합니다.
  3. 프로세스를 건너 뛰고 테스트를 우회해야하는 적절한 이유가 있습니다.

2
개발자가 개인 지점 또는 로컬 저장소에 체크인 할 수있게함으로써 # 1을 제거 할 수 있습니다. 개발자가 단위 테스트를 실행해야하는 다른 개발자가 볼 수있는 코드를 원하는 경우에만 해당됩니다. # 1과 마찬가지로 # 2는 메인 라인 분기에 대한 후크만으로 제거됩니다. # 3은 A) 그러한 기능이 번거 로움 (그리고 비록 비활성화 할 수 있다는 사실에 의해 없어진다 한다 귀찮은 일) 및 B) 개별 유닛 실패한 테스트를 사용할 수있다.
Brian

@Brian, 나는 전적으로 동의합니다, 당신은이 일을 할 수 있습니다. 그러나 커밋 후크 서버 측을 차단하여 시도하는 것은 효과가 없습니다.
Winston Ewert

좋은 지적. Breaking the build is simply too costly in terms of lost time for all engineers on the project나는 모든 엔지니어가 각 부서 빌드 시간을 잃어버린 결말을 피하기 위해 빌드 알림 도구의 일종을 사용하는 것이 좋습니다 것입니다
제리 요셉에게

3

아니요, 다른 답변이 지적한 것처럼해서는 안됩니다.

테스트 실패를 보장하지 않는 코드 기반을 원한다면 기능 분기를 개발하고 요청을 마스터로 끌어 올 수 있습니다. 그런 다음 해당 풀 요청을 수락하기위한 사전 조건을 정의 할 수 있습니다. 이점은 실제로 빠르게 푸시 할 수 있고 테스트가 백그라운드에서 실행된다는 것입니다.


2

메인 브랜치에 대한 각 커밋에 대한 성공적인 빌드 및 테스트를 기다려야한다는 것은 정말 끔찍합니다. 모두가 이것에 동의한다고 생각합니다.

그러나 일관된 메인 브랜치를 달성하는 다른 방법이 있습니다. 다음은 한 가지 제안입니다. TFS의 게이트 체크인과 유사하지만 분기가있는 모든 버전 제어 시스템에서 일반화 할 수 있지만 대부분 git 용어를 사용합니다.

  • 개발 브랜치와 기본 브랜치 간의 병합 만 커밋 할 수있는 준비 브랜치가 있습니다.

  • 빌드를 시작하거나 큐에 대기하고 스테이징 브랜치에서 수행 된 커밋을 테스트하는 후크를 설정하지만 커미터가 대기하지는 않습니다.

  • 성공적인 빌드 및 테스트에서 메인 지점 이 최신 상태 인 경우 자동으로 진행

    참고 : 테스트 된 병합은 기본 분기의 관점에서 정방향 병합이 아닌 경우 사이에 커밋이있는 기본 분기로 병합 될 때 실패 할 수 있으므로 자동으로 기본 분기로 병합 하지 마십시오.

결과로서:

  • 가능하면 자동으로 주 지점에 대한 사람의 커밋을 금지하지만 허점이 있거나 기술적으로 시행 할 수없는 경우 공식 프로세스의 일부로

    적어도 일단 기본 규칙이되면 아무도 의도 치 않게 또는 악의없이 행동하지 않도록 할 수 있습니다. 절대로 시도하지 마십시오.

  • 다음 중에서 선택해야합니다.

    • 이전의 아직 빌드되지 않았고 테스트되지 않은 병합이 실패하면 성공적인 병합을 실제로 수행하는 단일 준비 지점

      적어도 어떤 병합이 실패했는지 알고 누군가에게 수정하도록해야하지만, 이후의 빌드 및 테스트 결과에 대한 버전 관리 시스템에 의한 병합은 사소하게 추적 할 수 없습니다.

      파일 주석 (또는 비난)을 볼 수 있지만 때로는 파일 변경 (예 : 구성)으로 인해 예기치 않은 위치에 오류가 발생할 수 있습니다. 그러나 이것은 드문 경우입니다.

    • 충돌이없는 성공적인 병합이 기본 분기에 도달 할 수 있도록하는 여러 준비 분기

      다른 준비 지점 에 충돌 하지 않는 병합 이있는 경우에도 마찬가지입니다. 하나의 합병이 다른 합병의 변경에 영향을 미치지 않는 경우에는 추적 성이 약간 더 좋습니다. 그러나 다시 말하지만 이것은 매일 또는 매주 걱정할 정도로 충분히 드물다.

      대부분 충돌하지 않는 병합을하려면 스테이징 브랜치를 팀, 레이어 또는 구성 요소 / 프로젝트 / 시스템 / 솔루션 (예 : 이름 지정)별로 현명하게 분할하는 것이 중요합니다.

      주 지점이 다른 병합으로 전달 된 경우 다시 병합해야합니다. 잘만되면 이것은 충돌하지 않는 병합이나 충돌이 거의없는 문제가 아닙니다.

게이트 된 체크인과 비교하여, 이점은 메인 브랜치가 앞으로 만 허용되고 변경 사항을 사이에 커밋 된 내용과 자동으로 병합하지 않기 때문에 메인 브랜치 작동을 보장한다는 것입니다. 따라서 세 번째 요점은 본질적인 차이입니다.


그러나 작업 브랜치가 있다는 점은 (일반적으로) 안정적인 릴리스를 보장하는 것이 아니라 동일한 코드에서 함께 작업하는 개발자로 인한 스 래싱을 줄이는 것입니다.
Telastyn

전 세계에 분산 된 대규모 팀이있는 대규모 레포가 있다면 그렇지 않습니다. 예를 들어, Microsoft는 Windows와 유사한 더 계층화 된 접근 방식을 사용합니다.
acelent

2

코드를 제출하기위한 게이트로 "통과 된 단위 테스트"를 선호합니다. 그러나이 작업을 수행하려면 몇 가지 사항이 필요합니다.

아티팩트를 캐시하는 빌드 프레임 워크가 필요합니다.

주어진 인공물과 함께 (성공적인) 테스트 실행에서 테스트 상태를 캐시하는 테스트 프레임 워크가 필요합니다.

이렇게하면 단위 테스트를 통과 한 체크인이 빠르며 (개발자가 체크인하기 전에 테스트를 확인할 때 작성된 소스에서 아티팩트까지 교차 확인), 단위 테스트가 실패한 사용자는 차단되고 개발자는 컴파일 및 테스트주기가 길기 때문에 커밋하기 전에 빌드를 확인하는 것이 편리합니다.


1

프로젝트와 "커밋"에서 실행되는 자동화 된 테스트의 범위에 따라 다릅니다.

체크인 트리거에서 실행하려는 테스트가 실제로 빠르거나 개발자 워크 플로가 그러한 체크인 후에 일부 관리 작업을 강제 수행하는 경우 중요하지 않다고 생각하고 개발자가 확인해야합니다. 가장 기본적인 테스트를 절대적으로 수행하는 것들. (나는 당신이 그런 방아쇠에서 가장 기본적인 테스트 만 실행한다고 가정합니다.)

그리고 속도 / 워크 플로가 허용된다고 생각합니다. 테스트에 실패한 다른 개발자에게 변경 사항을 적용하지 않는 것이 좋습니다. 테스트를 실행하면 실패하는 경우에만 알 수 있습니다.

질문에 "원격 지점에 커밋 ..."이라고 쓰면 이것은 (a) 개발자가 몇 분마다 수행하는 작업이 아니기 때문에 작은 대기 시간이 매우 잘 받아 들여질 수 있습니다. 이러한 커밋 코드 변경 사항은 다른 개발자에게 영향을 줄 수 있으므로 추가 검사가 필요할 수 있습니다.

나는 그러한 작업을 기다리는 동안 "당신의 개발자가 기다리는 동안 엄지 손가락을 만들지 마십시오"에 대한 다른 답변에 동의 할 수 있습니다.


1

트렁크는 프로덕션에 들어갈 수 있기 때문에 깨진 커밋은 trunk에 허용되지 않아야합니다 . 따라서 트렁크에 가기 전에 통과해야하는 게이트웨이가 있는지 확인해야합니다 . 그러나 깨진 커밋은 트렁크에없는 한 리포지토리에서 완전히 괜찮을 수 있습니다.

반면에 저장소에 변경 사항을 적용하기 전에 개발자가 문제를 기다리거나 수정하도록 요구하는 데는 여러 가지 단점이 있습니다.

몇 가지 예 :

  • TDD에서는 기능 구현을 시작하기 전에 새 기능에 대해 실패한 테스트를 커밋하고 푸시하는 것이 일반적입니다.
  • 실패한 테스트를 커밋하고 푸시하여 버그를보고하는 것도 마찬가지입니다.
  • 불완전한 코드를 푸시하면 2 명 이상의 사람들이 기능을 쉽게 병렬로 작업 할 수 있습니다
  • CI 인프라를 확인하는 데 시간이 걸릴 수 있지만 개발자는 기다릴 필요가 없습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.