광범위하게 조롱하지 않고 어떻게 단위 테스트를 작성해야합니까?


80

내가 이해했듯이 단위 테스트의 요점 은 코드 단위를 격리 하여 테스트하는 것 입니다. 이는 다음을 의미합니다.

  1. 코드 베이스의 다른 곳에서 관련되지 않은 코드 변경으로 인해 깨지지 않아야합니다 .
  2. 통합 테스트 (힙에서 깨질 수 있음)와 반대로 테스트 된 장치의 버그로 인해 하나의 단위 테스트 만 중단해야합니다.

이 모든 것은 테스트 된 장치의 모든 외부 종속성을 조롱해야 함을 의미합니다. 그리고 네트워킹, 파일 시스템, 데이터베이스 등과 같은 "외부 레이어"뿐만 아니라 모든 외부 종속성을 의미 합니다 .

이것은 사실상 모든 단위 테스트가 조롱해야 한다는 논리적 인 결론으로 ​​이어진다 . 반면에, 조롱에 대한 Google의 빠른 검색은 "조롱은 코드 냄새"라고 주장하며 대부분 (완전히는 아니지만) 피해야하는 수많은 기사를 보여줍니다.

이제 질문에.

  1. 단위 테스트는 어떻게 올바르게 작성해야합니까?
  2. 그들과 통합 테스트 사이의 경계는 정확히 어디에 있습니까?

업데이트 1

다음 의사 코드를 고려하십시오.

class Person {
    constructor(calculator) {}

    calculate(a, b) {
        const sum = this.calculator.add(a, b);

        // do some other stuff with the `sum`
    }
}

의존성 Person.calculate을 조롱하지 않고 메소드를 테스트하는 테스트 Calculator( Calculator'외부 세계'에 액세스하지 않는 경량 클래스 임)를 단위 테스트로 간주 할 수 있습니까?


10
이것의 일부는 시간과 함께 올 디자인 경험입니다. 종속성을 조롱하기가 어렵지 않도록 구성 요소를 구성하는 방법을 배웁니다. 즉, 테스트 가능성은 모든 소프트웨어의 2 차 설계 목표 여야합니다. 테스트가 코드와 함께 또는 코드와 함께 작성되는 경우 (예 : TDD 및 / 또는 BDD 사용)이 목표를 훨씬 쉽게 충족 할 수 있습니다.
amon

33
빠르고 안정적으로 실행되는 테스트를 하나의 폴더에 넣습니다. 느리고 잠재적으로 취약한 테스트를 다른 테스트에 넣습니다. 가능한 한 자주 첫 번째 폴더에서 테스트를 실행하십시오 (문자를 입력 할 때 일시 정지 할 때마다 코드 컴파일이 이상적이지만 모든 개발 환경에서이를 지원하지는 않습니다). 더 느린 테스트는 덜 자주 실행하십시오 (예를 들어 커피 브레이크가있을 때). 단위 및 통합 이름에 대해 걱정하지 마십시오. 원하는 경우 빠르고 느리게 호출하십시오. 중요하지 않습니다.
David Arno

6
"거의 모든 단위 테스트는 조롱해야합니다" 그래요? 조롱 코드 냄새 ""입니다 "조롱에 대한 빠른 Google 검색은 주장 기사의 톤을 보여준다" 그들이 틀렸다을 .
Michael

13
@Michael 단순히 '그렇다'라고 말하고 반대 의견을 잘못 선언하는 것은 이와 같은 논쟁적인 주제에 접근하는 좋은 방법이 아닙니다. 아마도 조롱이 어디에나 있어야한다고 생각하는지, 왜 '기사'가 본질적으로 잘못되었다고 생각하는지에 대한 답을 작성하고 자세히 설명해보십시오.
AJFaraday

6
"조롱은 코드 냄새"에 대한 인용을하지 않았기 때문에, 당신이 읽은 내용을 잘못 해석하고 있다고 추측 할 수 있습니다. 조롱은 코드 냄새가 아닙니다. 모의 품을 주입하기 위해 반사 또는 다른 쉐넌 니온을 사용해야하는 것은 코드 냄새입니다. 조롱의 어려움은 API 디자인의 품질에 반비례합니다. 모의자를 생성자에게 전달하는 간단한 간단한 단위 테스트를 작성할 수 있다면 올바르게 수행하는 것입니다.
TKK

답변:


59

단위 테스트의 포인트는 코드 단위를 개별적으로 테스트하는 것입니다.

단위 테스트 에 마틴 파울러

단위 테스트는 종종 소프트웨어 개발에서 언급되며, 프로그램을 작성하는 동안 익숙한 용어입니다. 그러나 대부분의 소프트웨어 개발 용어와 마찬가지로 정의가 매우 잘못되어 사람들이 실제보다 더 엄격하게 정의되었다고 생각할 때 혼란이 종종 발생할 수 있습니다.

Kent Beck이 테스트 중심 개발 에서 작성한 내용

"단위 테스트"라고하지만 허용 된 단위 테스트 정의와 일치하지 않습니다.

"단위 테스트 포인트"라는 주어진 주장은 "단위 테스트"의 정의가 고려되는 것에 크게 좌우 될 것이다.

프로그램이 서로 의존하는 많은 작은 단위로 구성되어 있고 각 단위를 독립적으로 테스트하는 스타일로 제한하는 경우 많은 테스트 배가 불가피한 결론입니다.

당신이 보는 상충되는 충고는 다른 가정에서 운영되는 사람들로부터 나옵니다.

예를 들어 리팩토링 프로세스 중에 개발자를 지원하기 위해 테스트를 작성하고 하나의 단위를 두 개로 나누는 것이 지원되어야하는 리팩토링 인 경우 무언가를 제공해야합니다. 아마도 이런 종류의 테스트에는 다른 이름이 필요할까요? 아니면 "단위"에 대한 다른 이해가 필요할 수도 있습니다.

다음을 비교할 수 있습니다.

계산기 의존성을 조롱하지 않고 Person.calculate 메소드를 테스트하는 테스트 (계산기는 "외부"에 액세스하지 않는 경량 클래스 임)를 단위 테스트로 간주 할 수 있습니까?

나는 이것이 잘못된 질문이라고 생각합니다. 우리가 실제로 관심을 갖는 것은 속성 이라고 생각할 때 레이블에 대한 논쟁 입니다.

코드에 변경 사항을 도입 할 때 테스트 격리에 신경 쓰지 않습니다. 이미 "확인되지 않은 편집 스택에"실수 "가 있다는 것을 알고 있습니다. 테스트를 자주 실행하면 해당 스택의 깊이를 제한하고 실수를 찾는 것이 사소한 것입니다 (극단적 인 경우 테스트는 모든 편집 후에 실행됩니다-스택의 최대 깊이는 1입니다). 그러나 테스트를 실행하는 것이 목표가 아니며 중단이므로 중단의 영향을 줄이는 데 가치가 있습니다. 중단을 줄이는 한 가지 방법은 테스트가 빠르다는 것입니다 ( Gary Bernhardt는 300ms 제안 하지만 내 상황에서 그렇게하는 방법을 찾지 못했습니다).

호출 Calculator::add이 테스트 실행에 필요한 시간 (또는이 사용 사례의 다른 중요한 속성)을 크게 증가시키지 않으면 테스트 이중 사용을 귀찮게하지 않을 것입니다. 비용을 능가하는 이점을 제공하지 않습니다. .

여기에서 비용 평가의 일부인 인간과 이익 평가에서 확인되지 않은 변경 사항의 짧은 스택이라는 두 가지 가정을 주목하십시오. 이러한 조건이 유지되지 않는 상황에서는 "격리"값이 약간 변경됩니다.

Harry Percival의 Hot Lava 도 참조하십시오 .


5
mocking add가하는 한 가지는 계산기 가 조롱 될 있다는 것을 증명하는 것입니다. 즉, 디자인이 사람과 계산기를 결합하지 않는 것입니다 (이것은 다른 방법으로도 확인할 수 있습니다)
jk.

40

광범위하게 조롱하지 않고 어떻게 단위 테스트를 작성해야합니까?

코드의 부작용을 최소화합니다.

calculator를 들어 웹 API와 통신하는 경우 예제 코드 를 사용하면 해당 웹 API와 상호 작용할 수있는 취약한 테스트를 만들거나 모의 객체를 만들 수 있습니다. 그러나 결정적이지 않고 상태가없는 계산 함수 세트 인 경우이를 조롱해서는 안됩니다. 그렇게하면 모의 코드가 실제 코드와 다르게 동작하여 테스트 버그가 발생할 위험이 있습니다.

파일 시스템, 데이터베이스, URL 엔드 포인트 등을 읽고 쓰는 코드에만 Mocks가 필요합니다. 실행중인 환경에 따라 다릅니다. 또는 매우 상태가 양호하고 비 결정적입니다. 따라서 코드의 해당 부분을 최소한으로 유지하고 추상화 뒤에 숨기면 모방하기 쉽고 코드의 나머지 부분은 모의 필요성을 피합니다.

부작용이있는 코드 포인트의 경우 모의 테스트를 작성하고 그렇지 않은 테스트를 작성하는 것이 좋습니다. 후자는 본질적으로 연약하고 느려질 수 있으므로주의가 필요하다. 따라서 코드를 저장하고 빌드 할 때마다 CI 서버에서 하룻밤 만 실행해야 할 수 있습니다. 그러나 이전 테스트는 가능한 한 자주 실행해야합니다. 각 테스트가 단위 테스트인지 통합 테스트인지에 대해서는 학문이되며 단위 테스트에 대한 "화염 전쟁"을 피합니다.


8
이것은 실제로 의미가없는 의미 론적 토론을 피하는 관점에서 정답입니다.
Jared Smith

그러한 스타일을 사용하면서도 좋은 테스트 범위를 얻는 사소한 오픈 소스 코드베이스의 예가 있습니까?
Joeri Sebrechts

4
@JoeriSebrechts는 모든 단일 FP 하나?
Jared Smith

내가 찾고있는 것은 아닙니다. 서로 독립적 인 함수 모음 일뿐 아니라 서로를 호출하는 함수 시스템이 아니기 때문입니다. 함수가 최상위 함수 중 하나 인 경우 테스트 목적으로 함수에 복잡한 인수를 구성해야하는 방법은 무엇입니까? 예를 들어 게임의 핵심 루프.
Joeri Sebrechts

1
@JoeriSebrechts 흠, 나는 당신이 원하는 것을 오해하고 있거나, 당신이 제시 한 예를 충분히 깊이 파고 들지 않았습니다. ramda 함수는 소스의 모든 곳에서 내부 호출을 사용합니다 (예 :) R.equals. 이것들은 대부분 순수한 기능을위한 것이기 때문에 일반적으로 테스트에서 조롱되지 않습니다.
Jared Smith

31

이 질문들은 어려움이 상당히 다릅니다. 2 번 문제를 먼저 봅시다.

단위 테스트와 통합 테스트는 명확하게 분리되어 있습니다. 단위 테스트는 하나의 단위 (방법 또는 클래스)를 테스트 하고 해당 목표를 달성하는 데 필요한만큼만 다른 단위를 사용합니다. 조롱이 필요할 수 있지만 시험의 요점은 아닙니다. 통합 테스트는 서로 다른 실제 장치 간의 상호 작용을 테스트합니다 . 이 차이는 단위 테스트와 통합 테스트 모두 필요한 이유입니다. 하나가 다른 하나의 작업을 충분히 수행했다면 그렇지 않을 것입니다. 그러나 일반적으로 하나의 일반화 된 도구가 아닌 두 개의 특수한 도구를 사용하는 것이 더 효율적이라는 것이 밝혀졌습니다 .

이제 중요한 질문 : 어떻게 단위 테스트를해야합니까? 위에서 언급했듯이 단위 테스트는 필요한만큼만 보조 구조를 구성해야 합니다 . 종종 실제 데이터베이스 또는보다 모의 데이터베이스를 사용하는 것이 더 쉽습니다 어떤 실제 데이터베이스. 그러나 조롱 자체는 가치가 없습니다. 종종 다른 레벨의 실제 컴포넌트를 중간 레벨 단위 테스트의 입력 으로 사용하는 것이 더 쉬운 경우가 종종 있습니다. 그렇다면 망설이지 말고 사용하십시오.

많은 실무자들은 만약 단위 테스트 B가 단위 테스트 A에 의해 이미 테스트 된 클래스를 재사용한다면, 단위 A의 결함이 여러 곳에서 테스트 실패를 야기 할 것을 두려워합니다. 나는 이것이 문제가 아니라고 생각한다. 테스트 스위트는 당신에게 필요한 확신을주기 위해 100 % 성공 해야하므로 너무 많은 실패를 겪는 것은 큰 문제가 아니다-결국, 당신 결함이있다. 결함이 너무 적은 실패를 유발 한 경우에만 중요한 문제가 발생 합니다.

그러므로 조롱의 종교를 만들지 마십시오. 그것은 끝이 아닌 수단이므로 추가 노력을 피하면서 도망 갈 수 있다면 그렇게해야합니다.


4
The only critical problem would be if a defect triggered too few failures.이것은 조롱의 약점 중 하나입니다. 예상되는 동작을 "프로그래밍"해야합니다. 그렇게하지 않으면 테스트가 "거짓 긍정"으로 끝나게됩니다. 그러나 조롱은 결정론 (테스트의 가장 중요한 조건)을 달성하기 위해 매우 유용한 기술입니다. 가능하면 모든 프로젝트에서 사용합니다. 또한 통합이 너무 복잡하거나 종속성이 너무 빡빡한 경우를 보여줍니다.
Laiv

1
테스트중인 장치가 다른 장치를 사용하는 경우 실제로 통합 테스트가 아닙니까? 본질적으로이 단위는 통합 테스트와 똑같이 상기 단위 간의 상호 작용을 테스트하기 때문입니다.
Alexander Lomia

11
@AlexanderLomia : 당신은 무엇을 단위라고 부를까요? 단위로 'String'을 호출 하시겠습니까? 나는 그것을 조롱하는 꿈을 꾸지 않을 것입니다.
바트 반 Ingen Schenau

5
" 단위 테스트와 통합 테스트는 명확하게 구분됩니다. 단위 테스트는 하나의 단위 (방법 또는 클래스)를 테스트하고 해당 목표를 달성하는 데 필요한만큼만 다른 단위를 사용합니다 ". 문지름이 있습니다. 이것이 단위 테스트 정의입니다. 광산은 상당히 다릅니다. 따라서 그들 사이의 구별은 주어진 정의에 대해서만 "명확하게 분리되어"있지만 정의 사이의 분리는 다양합니다.
David Arno

4
@Voo 이러한 코드베이스로 작업 한 결과 원래 문제를 발견하는 것은 성가신 일이 될 수 있지만 (특히 아키텍처가 디버깅에 사용하는 것을 페인트 한 경우), 여전히 모의에서 더 많은 문제가 발생했습니다. 테스트에 사용 된 코드가 손상된 후에도 계속 작동합니다.
James_pic

6

질문에 직접 대답하려면 다음을 수행하십시오.

단위 테스트는 어떻게 올바르게 작성해야합니까?

당신이 말했듯이, 당신은 의존성을 조롱하고 문제의 단위만을 테스트해야합니다.

그들과 통합 테스트 사이의 경계는 정확히 어디에 있습니까?

통합 테스트는 종속성이 조롱되지 않은 단위 테스트입니다.

계산기를 조롱하지 않고 Person.calculate 메서드를 테스트하는 테스트를 단위 테스트로 간주 할 수 있습니까?

아니요.이 코드에 계산기 의존성을 주입해야하며 모의 버전 또는 실제 버전 중에서 선택할 수 있습니다. 모의 테스트를 사용하여 단위 테스트를 사용하는 경우 실제 테스트를 사용하여 통합 테스트를 수행하는 경우.

그러나주의 사항. 사람들이 테스트를 호출해야한다고 생각하는 것이 정말로 중요합니까?

그러나 당신의 실제 질문은 다음과 같습니다.

조롱에 대한 빠른 Google 검색은 "조롱은 코드 냄새"라고 주장하며 대부분 (완전히는 아니지만) 피해야하는 많은 기사를 보여줍니다.

여기서 문제는 많은 사람들이 모의를 사용하여 종속성을 완전히 재현한다는 것입니다. 예를 들어 귀하의 예에서 계산기를 조롱 할 수 있습니다.

public class MockCalc : ICalculator
{
     public Add(int a, int b) { return 4; }
}

나는 다음과 같은 일을하지 않을 것입니다 :

myMock = Mock<ICalculator>().Add((a,b) => {return a + b;})
myPerson.Calculate()
Assert.WasCalled(myMock.Add());

나는 이것이 "모의 테스트"또는 "구현 테스트"라고 주장 할 것이다. 나는 " Mock을 쓰지 마라! 그런 식으로" 라고 말할 것이다 .

다른 사람들은 저와 동의하지 않을 것입니다. 블로그에서 Mock으로가는 가장 좋은 방법에 대해 엄청난 화염 전쟁을 시작할 것입니다. 좋은 시험을보고 싶은 사람에게.


철저한 답변에 감사드립니다. 다른 사람들이 내 테스트에 대해 어떻게 생각하는지 걱정할 때 실제로는 프로젝트가 진행됨에 따라 반 통합, 반 단위 테스트를 작성하는 것이 신뢰할 수 없게 엉망이되는 경향이 있습니다.
Alexander Lomia

문제는 없습니다. 문제는 두 가지의 정의가 모두가 100 % 동의하지 않았다는 것입니다.
Ewan

나는 당신의 클래스 이름을 바꿀 것 MockCalc까지를 StubCalc, 그리고 그루터기하지 모의를 호출합니다. martinfowler.com/articles/…
bdsl

@bdsl이 기사는 15 살입니다
Ewan

4
  1. 단위 테스트는 어떻게 올바르게 구현해야합니까?

제 경험에 따르면 적절한 단위 테스트는 다음과 같습니다.

  • 구현이 아닌 인터페이스에 대해 코딩됩니다 . 이것은 많은 이점이 있습니다. 우선, 클래스 가 SOLIDDependency Inversion Principle 을 따릅니다 . 또한 이것은 다른 클래스가하는 일 ( 맞습니까? )이므로 테스트는 동일하게 수행되어야합니다. 또한 많은 테스트 코드를 재사용하면서 동일한 인터페이스의 여러 구현을 테스트 할 수 있습니다 (초기화 및 일부 어설 션 만 변경됨).
  • 독립적 입니다. 말했듯이 외부 코드의 변경은 테스트 결과에 영향을 줄 수 없습니다. 따라서 단위 테스트는 빌드 타임에 실행될 수 있습니다. 즉, 부작용을 제거하려면 모의가 필요합니다. 그러나 Dependency Inversion Principle을 따르는 경우 비교적 쉽습니다. Spock 과 같은 우수한 테스트 프레임 워크 를 사용하면 최소한의 코딩으로 테스트에 사용할 인터페이스의 모의 구현을 동적으로 제공 할 수 있습니다. 즉, 각 테스트 클래스는 정확히 하나의 구현 클래스와 테스트 프레임 워크 (및 모델 클래스 [ "beans"])의 코드 만 실행하면됩니다.
  • 별도의 실행중인 응용 프로그램이 필요하지 않습니다 . 데이터베이스 또는 웹 서비스에 관계없이 테스트가 "무언가와 통신"해야하는 경우 단위 테스트가 아니라 통합 테스트입니다. 네트워크 연결이나 파일 시스템에 선을 그립니다. 예를 들어 순수하게 메모리 내 SQLite 데이터베이스는 실제로 필요한 경우 단위 테스트에 대한 공정한 게임입니다.

단위 테스트를 복잡하게하는 프레임 워크의 유틸리티 클래스가있는 경우 이러한 종속성을 조롱하기 위해 매우 간단한 "래퍼"인터페이스 및 클래스를 작성하는 것이 유용 할 수도 있습니다. 이러한 래퍼는 반드시 단위 테스트를받을 필요는 없습니다.

  1. [단위 테스트]와 통합 테스트 사이의 선은 정확히 어디에 있습니까?

이 구별이 가장 유용한 것으로 나타났습니다.

  • 단위 테스트는 "사용자 코드"를 시뮬레이트 하여 원하는 코드 수준 인터페이스 의 동작 및 의미에 대해 구현 클래스의 동작을 확인 합니다.
  • 통합 테스트는 사용자를 시뮬레이션하여 지정된 사용 사례 및 / 또는 공식 API에 대해 실행중인 응용 프로그램의 동작을 확인 합니다. 웹 서비스의 경우 "사용자"는 클라이언트 응용 프로그램입니다.

여기에 회색 영역이 있습니다. 예를 들어, Docker 컨테이너에서 애플리케이션을 실행하고 빌드의 최종 단계로 통합 테스트를 실행하고 나중에 컨테이너를 파기 할 수있는 경우 해당 테스트를 "단위 테스트"로 포함해도 괜찮습니까? 이것이 당신의 불타는 논쟁이라면, 당신은 꽤 좋은 곳에 있습니다.

  1. 사실상 모든 단위 테스트가 조롱해야합니까?

아니요. 일부 개별 테스트 사례는 null매개 변수로 전달 하고 예외가 있는지 확인 하는 등의 오류 조건에 대한 것 입니다. 이와 같은 많은 테스트는 모의가 필요하지 않습니다. 또한 문자열 처리 또는 수학 함수와 같은 부작용이없는 구현에는 단순히 출력을 확인하기 때문에 모의가 필요하지 않을 수 있습니다. 그러나 생각할 가치가있는 대부분의 클래스는 테스트 코드 어딘가에 적어도 하나의 모의가 필요하다고 생각합니다. (작을수록 좋습니다.)

언급 한 "코드 냄새"문제는 지나치게 복잡한 클래스가있을 때 발생하며, 테스트를 작성하려면 모의 종속성이 많이 있어야합니다. 이것은 각 클래스가 더 작은 설치 공간과 더 명확한 책임을 갖기 때문에 구현을 리팩토링하고 사물을 분할해야한다는 단서이며, 따라서 더 쉽게 테스트 할 수 있습니다. 이것은 장기적으로 품질을 향상시킵니다.

테스트 된 장치의 버그로 인해 하나의 단위 테스트 만 중단됩니다.

나는 이것이 재사용에 반대하기 때문에 합리적인 기대라고 생각하지 않습니다. 당신은 할 수 있습니다 private다수에 의해 불려 예를 들면 방법, public사용자 인터페이스에 의해 게시 방법. 한 가지 방법으로 버그가 발생하면 여러 번의 테스트 실패가 발생할 수 있습니다. 그렇다고 각 코드에 동일한 코드를 복사해야한다는 의미는 아닙니다 public.


3
  1. 코드 베이스의 다른 곳에서 관련되지 않은 코드 변경으로 인해 깨지지 않아야합니다 .

이 규칙이 어떻게 유용한 지 잘 모르겠습니다. 한 클래스 / 메소드 / 무엇이 변경되어 프로덕션 코드에서 다른 클래스의 동작을 중단시킬 수있는 경우 실제로는 협력자이며 관련이 없습니다. 테스트가 중단되고 프로덕션 코드가 실패하면 테스트가 의심됩니다.

  1. 통합 테스트 (힙에서 깨질 수 있음)와 반대로 테스트 된 장치의 버그로 인해 하나의 단위 테스트 만 중단해야합니다.

나는이 규칙을 의심으로 여길 것이다. 하나의 버그가 정확히 하나의 단위 테스트 실패를 유발하도록 코드를 구성하고 테스트를 작성하기에 충분하다면 코드베이스가 사용 사례를 발전시키기 위해 이미 모든 잠재적 버그를 식별했다고 말하고 있습니다. 예상하지 못했습니다.

그들과 통합 테스트 사이의 경계는 정확히 어디에 있습니까?

나는 그것이 중요한 구별이라고 생각하지 않습니다. 어쨌든 코드의 '단위'는 무엇입니까?

해당 수준 의 코드가 처리 하는 문제 도메인 / 비즈니스 규칙의 관점에서 '합리적인'테스트를 작성할 수있는 진입 점을 찾으십시오 . 종종 이러한 테스트는 본질적으로 다소 '기능적'입니다. 입력을 넣고 출력이 예상 한대로 테스트하십시오. 테스트에서 시스템의 원하는 동작을 나타내는 경우 프로덕션 코드가 발전하고 리팩토링 된 경우에도 종종 안정적으로 유지됩니다.

광범위하게 조롱하지 않고 어떻게 단위 테스트를 작성해야합니까?

'단위'라는 단어를 너무 많이 읽지 말고 테스트에 둘 이상을 포함하더라도 너무 걱정하지 않고 테스트에서 실제 프로덕션 클래스를 사용하는 것에 의존하십시오. 그중 하나가 사용하기 어려운 경우 (초기화가 많이 걸리거나 실제 데이터베이스 / 전자 메일 서버 등을 사용해야하기 때문에) 모의 / 가짜로 생각하십시오.


" 어쨌든 코드의 '단위'란 무엇입니까? "누가 응답하는지에 따라 예상치 못한 답변을 얻을 수있는 매우 좋은 질문입니다. 일반적으로 단위 테스트의 대부분의 정의는 메소드 또는 클래스와 관련하여 설명하지만 모든 경우에 "단위"의 유용한 측정 방법은 아닙니다. 내가 Person:tellStory()사람의 세부 사항을 문자열로 통합 하는 방법 이 있다면 그것을 반환하면 "스토리"는 아마도 하나의 단위 일 것입니다. 일부 코드를 숨기는 개인 도우미 메서드를 만들면 새로운 단위를 도입했다고 생각하지 않습니다. 별도로 테스트 할 필요가 없습니다.
VLAZ

1

먼저 일부 정의는 다음과 같습니다.

단위 테스트는 단위를 다른 단위와 분리하여 테스트 하지만 그 의미가 신뢰할 수있는 소스에 의해 구체적으로 정의되어 있지 않으므로 조금 더 잘 정의 해 보겠습니다. 화면 또는 UI 입력)에 선을 그릴 수있는 객관적인 장소가 있습니다. 코드가 I / O에 의존하는 경우 코드가 단위 경계를 넘어서므로 해당 I / O를 담당하는 단위를 조롱해야합니다.

그 정의에 따르면 순수한 함수와 같은 것을 조롱해야 할 강력한 이유는 없습니다. 즉, 단위 테스트가 순수한 함수 또는 부작용이없는 함수에 적합하다는 것을 의미합니다.

효과가있는 단위를 테스트하려면 효과를 담당하는 단위를 조롱해야하지만 대신 통합 테스트를 고려해야합니다. 따라서 대답은 "모의해야 할 경우 실제로 필요한 것이 통합 테스트인지 스스로에게 물어보십시오"입니다. 그러나 여기에 더 좋고 더 긴 대답이 있으며 토끼 구멍이 훨씬 깊어집니다. Mocks는 배울 것이 너무 많기 때문에 내가 좋아하는 코드 냄새 일 수 있습니다.

코드 냄새

이를 위해 Wikipedia를 보겠습니다.

컴퓨터 프로그래밍에서 코드 냄새는 더 깊은 문제를 나타낼 수있는 프로그램 소스 코드의 특성입니다.

나중에 계속됩니다 ...

"냄새는 기본 설계 원칙을 위반하고 설계 품질에 부정적인 영향을 미치는 코드의 특정 구조입니다." Girish의 Suryanarayana (2014 년 11 월). 소프트웨어 설계 냄새에 대한 리팩토링. 모건 카우프만 피. 258.

코드 냄새는 일반적으로 버그가 아닙니다. 그것들은 기술적으로 부정확하지 않으며 프로그램의 기능을 방해하지 않습니다. 대신, 설계의 약점을 나타내어 개발 속도를 늦추거나 향후 버그 또는 장애의 위험을 증가시킬 수 있습니다.

다시 말해, 모든 코드 냄새가 나쁜 것은 아닙니다. 대신, 그것들은 무언가가 최적의 형태로 표현되지 않을 수 있다는 일반적인 표시이며, 냄새 문제의 코드를 개선 할 기회를 나타낼 수 있습니다 .

조롱의 경우, 냄새는 조롱을 요구하는 것으로 보이는 유닛이 조롱 할 유닛에 의존 한다는 것을 나타냅니다 . 그것은 우리가 원자 - 풀 수 조각으로 문제를 분해하지 않은 표시를 할 수 있으며, 소프트웨어의 설계 결함을 나타낼 수 있습니다.

모든 소프트웨어 개발의 본질은 큰 문제를 더 작고 독립적 인 조각으로 분해하고 (분해) 솔루션을 함께 구성하여 큰 문제 (조성)를 해결하는 응용 프로그램을 형성하는 프로세스입니다.

큰 문제를 작은 부분으로 나누는 데 사용되는 장치가 서로 의존 할 때 조롱이 필요합니다. 달리 말하면, 우리의 구성 원자 단위가 실제로 원자 적이 지 않을 때 조롱이 필요하며, 우리의 분해 전략은 더 큰 문제를 더 작고 독립적 인 문제로 분해하지 못했습니다 .

코드 조롱을 조롱하는 것은 조롱에 본질적으로 문제가 있다는 것이 아닙니다. 때로는 매우 유용합니다. 코드 냄새가 나는 것은 응용 프로그램에서 문제가있는 커플 링 소스를 나타낼 수 있다는 것입니다. 때로는 해당 소스를 제거하는 것이 모형을 쓰는 것보다 훨씬 생산적입니다.

많은 종류의 커플 링이 있으며 일부는 다른 것보다 낫습니다. 모의가 코드 냄새라는 것을 이해 하면 냄새가 더 심해 지기 전에 응용 프로그램 설계 수명주기 초기 에 최악의 종류를 식별하고 피하도록 지시 할 수 있습니다 .


0

조롱은 단위 테스트에서도 최후의 수단으로 만 사용해야합니다.

메소드는 단위가 아니며 클래스조차도 단위가 아닙니다. 단위는 호출 한 코드에 상관없이 의미가있는 논리적 코드 분리입니다. 잘 테스트 된 코드를 갖는 중요한 요소는 자유롭게 리팩토링 할 수 있으며, 자유롭게 리팩터링 할 수 있다는 것은 테스트를 변경하기 위해 변경할 필요가 없다는 것을 의미합니다. 조롱할수록 리팩토링 할 때 테스트를 더 많이 변경해야합니다. 단위를 분석법으로 간주하는 경우 리팩토링 할 때마다 테스트를 변경해야합니다. 클래스를 단위로 생각하면 클래스를 여러 클래스로 나눌 때마다 테스트를 변경해야합니다. 코드를 리팩터링하기 위해 테스트를 리팩터링해야하는 경우 사람들은 코드를 리팩터링하지 않도록 선택합니다. 이는 프로젝트에서 발생할 수있는 최악의 상황입니다. 테스트를 리팩터링하지 않고 클래스를 여러 클래스로 나눌 수 있어야합니다. 그렇지 않으면 500 줄의 대형 스파게티 클래스가 생길 수 있습니다. 단위 테스트를 통해 메소드 또는 클래스를 단위로 처리하는 경우 객체 지향 프로그래밍을 수행하지 않고 객체를 사용한 일종의 돌연변이 기능 프로그래밍을 수행하고있을 것입니다.

단위 테스트를 위해 코드를 분리한다고해서 외부의 모든 것을 조롱한다는 의미는 아닙니다. 그렇다면 언어의 수학 수업을 조롱해야하며 아무도 좋은 생각이라고 생각하지 않습니다. 내부 종속성은 외부 종속성과 다르게 취급해서는 안됩니다. 당신은 그들이 잘 테스트되고 예상대로 작동한다고 믿습니다. 유일한 차이점은 내부 종속성이 모듈을 손상시키는 경우 GitHub에 문제를 게시하지 않고 모듈을 수정하기 위해 이해하지 못하는 코드베이스를 파지 않고 모듈을 수정하기 위해 수행중인 작업을 중지 할 수 있다는 것입니다 또는 최선을 다하겠습니다.

코드를 격리한다는 것은 내부 종속성을 블랙 박스처럼 취급하고 내부에서 발생하는 것을 테스트하지 않음을 의미합니다. 1, 2 또는 3의 입력을 허용하는 모듈 B가 있고이를 호출하는 모듈 A가있는 경우, 모듈 A에 대한 테스트에서 해당 옵션 각각을 수행하지 않아도됩니다. 하나만 선택하여 사용하십시오. 이는 모듈 A에 대한 테스트가 모듈 B의 응답을 처리하는 방식이 아니라 모듈 B의 응답을 처리하는 다양한 방법을 테스트해야 함을 의미합니다.

따라서 컨트롤러가 복잡한 객체를 종속성으로 전달하고 해당 종속성이 여러 가지 가능한 작업을 수행하면 데이터베이스에 저장하고 다양한 오류를 반환 할 수 있지만 실제로 모든 컨트롤러는 단순히 반환되는지 확인하는 것입니다. 오류 여부와 해당 정보를 함께 전달하면 컨트롤러에서 테스트하는 것은 오류를 반환하는지 한 번 테스트하고 오류를 반환하지 않으면 한 번의 테스트입니다. 데이터베이스에 무언가가 저장되었는지 또는 오류가 어떤 종류의 오류인지 테스트하지 않습니다. 통합 테스트이기 때문입니다. 이를 위해 종속성을 조롱 할 필요는 없습니다. 코드를 분리했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.