Dev

[번역] UnitTest: Martin Fowler

November 11, 2018

[번역] UnitTest: Martin Fowler

마틴 파울러의 UnitTest를 번역 했습니다. 영어 실력이 일천해 오역이 많을 수 있습니다. 의견 주시면 적극적으로 반영하겠습니다.


Unit testing is often talked about in software development, and is a term that I’ve been familiar with during my whole time writing programs. Like most software development terminology, however, it’s very ill-defined, and I see confusion can often occur when people think that it’s more tightly defined than it actually is.

소프트웨어 개발에서 단위 테스트는 자주 회자되고, 내가 프로그램을 작성해오면서 언제나 친근하게 느껴온 용어이기도 하다. 그러나 대부분의 소프트웨어 용어처럼 단위 테스트는 잘못 정의되어 있으며, 사람들이 단위 테스트를 실제보다 더 엄격하게 정의되어 있다고 생각할 때 혼란이 발생할 수 있다.

Although I’d done plenty of unit testing before, my definitive exposure was when I started working with Kent Beck and used the Xunit family of unit testing tools. (Indeed I sometimes think a good term for this style of testing might be “xunit testing.”) Unit testing also became a signature activity of ExtremeProgramming (XP), and led quickly to TestDrivenDevelopment.

나는 전부터 많은 단위 테스트를 해봤지만, 내가 Kent Beck과 Xunit 그룹의 단위 테스트 도구를 사용하면서 일을 시작했을 때가 단위 테스트를 접한 결정적 계기가 되었다. (그래서 나는 “xunit testing”이 이런 테스팅 스타일 위한 좋은 용어라고 생각했다.) 또한 단위 테스팅은 ExtreamProgramming(XP)의 대표적인 활동이고, TestDrivenDevelopment로 빠르게 이어졌다.

There were definitional concerns about XP’s use of unit testing right from the early days. I have a distinct memory of a discussion on a usenet discussion group where us XPers were berated by a testing expert for misusing the term “unit test.” We asked him for his definition and he replied with something like “in the morning of my training course I cover 24 different definitions of unit test.”

최근에 XP의 단위 테스팅 사용에 관련된 고민들이 있었다. 나는 usenet 토론 그룹에서의 토론에서 우리 XPer들이 “unit test”라는 단어의 오용 때문에 테스트 전문가에게 배신 당했던 뚜렷한 기억이 있다. 우리는 그에게 그가 생각하는 정의를 물어봤더니, 그는 “아침 훈련 코스에서 나는 단위 테스트에 대한 24개의 다른 정의를 다뤘다” 같은 대답을 했다.

Despite the variations, there are some common elements. Firstly there is a notion that unit tests are low-level, focusing on a small part of the software system. Secondly unit tests are usually written these days by the programmers themselves using their regular tools – the only difference being the use of some sort of unit testing framework [1]. Thirdly unit tests are expected to be significantly faster than other kinds of tests.

다양한 해석에도 불구하고 몇 가지 공통된 요소가 있다. 첫 번 째로 단위 테스트는 낮은 수준이고 시스템의 작은 부분에만 집중한다. 두 번 째로 요즘은 개발자 스스로가 편한 도구를 사용해서 스스로 단위 테스트를 작성한다 – 차이는 그저 몇 가지 단위 테스팅 프레임워크를 사용하는 것이다. 세 번 째는 단위 테스트는 다른 종류의 테스트들에 비해서 상당히 빠르다.

So there’s some common elements, but there are also differences. One difference is what people consider to be a unit. Object-oriented design tends to treat a class as the unit, procedural or functional approaches might consider a single function as a unit. But really it’s a situational thing – the team decides what makes sense to be a unit for the purposes of their understanding of the system and its testing. Although I start with the notion of the unit being a class, I often take a bunch of closely related classes and treat them as a single unit. Rarely I might take a subset of methods in a class as a unit. However you define it doesn’t really matter.

몇 가지 공통 요소들이 있지만 차이점도 있다. 첫 번 째는 무엇이 단위가 되어야 하냐는 것이다. 객체지향 디자인은 클래스를 단위로 취급하는 경향이 있고, 절차적 또는 함수형 접근은 하나의 함수를 단위로 생각할 수도 있다. 그러나 단위는 상황적인 것이다 – 시스템과 테스팅을 이해하기 위해 무엇이 단위가 되는 것이 합리적인지는 팀이 (그때그때)정하는 것이다. 비록 내가 클래스를 단위로 취급하는 개념으로 시작했다고는 하지만, 종종 관련된 여러 클래스들을 하나의 단위로 취급하기도 하고, 드물게는 클래스 메소드들의 부분 집합을 하나의 단위로 삼을 수도 있다. 이런 것을 정의하는 것은 전혀 중요하지 않다.

Solitary or Sociable? (고립? 통합?)

A more important distinction is whether the unit you’re testing should be sociable or solitary [2]. Imagine you’re testing an order class’s price method. The price method needs to invoke some functions on the product and customer classes. If you like your unit tests to be solitary, you don’t want to use the real product or customer classes here, because a fault in the customer class would cause the order class’s tests to fail. Instead you use TestDoubles for the collaborators.

더 중요한 차이는 당신이 테스트하는 단위가 통합되어야 하는지 고립되어야 하는지이다. 당신이 주문 클래스의 가격 메소드를 테스트 중이라고 상상해보라. 가격 메소드는 상품과 고객 클래스들의 어떤 함수를 실행시커야 한다. 만약 당신이 단위 테스트가 고립 되기를 바란다면, 당신은 이 테스트에서 실제 상품, 고객 클래스를 쓰고 싶지는 않을 것이다. 왜냐하면 고객 클래스에서의 실패가 주문 클래스 테스트에서의 실패로 이어질 것이기 때문이다. 대신 연관된 작업을 위한 TestDoubles을 사용한다.

But not all unit testers use solitary unit tests. Indeed when xunit testing began in the 90’s we made no attempt to go solitary unless communicating with the collaborators was awkward (such as a remote credit card verification system). We didn’t find it difficult to track down the actual fault, even if it caused neighboring tests to fail. So we felt allowing our tests to be sociable didn’t lead to problems in practice.

그러나 모든 단위 테스트를 고립 단위 테스트로 만든 것은 아니다. 실제로 xunit 테스팅이 시작했을 때인 90년대에는 연동 시스템과의 통신이 이상한 경우가 아니라면(원격 신용카드 확인 시스템 같은) 고립 테스트로 가려는 시도조차 없었다. 심지어 이웃 테스트의 실패가 원인일지라도 실제 문제점이 무엇인지 찾는 것이 어렵지는 않았다. 그래서 우리의 테스트들이 통합 되도록 두는 것이 실제로 문제를 일으키지 않는다고 느겼다.

Indeed using sociable unit tests was one of the reasons we were criticized for our use of the term “unit testing”. I think that the term “unit testing” is appropriate because these tests are tests of the behavior of a single unit. We write the tests assuming everything other than that unit is working correctly.

실제로 통합된 단위 테스트를 사용하는 것은 “단위 테스팅”이라는 용어 사용에 대해 비판해왔던 이유 중에 하나였다. 테스트들이 한 개의 단위 행동만 테스트할 때만 “단위 테스팅”이라는 용어가 적절하다고 생각한다. 우리는 그 단위 이외의 모든 것들이 정확하게 동작한다고 가정하고 테스트를 작성한다.

As xunit testing became more popular in the 2000’s the notion of solitary tests came back, at least for some people. We saw the rise of Mock Objects and frameworks to support mocking. Two schools of xunit testing developed, which I call the classic and mockist styles. One of the differences between the two styles is that mockists insist upon solitary unit tests, while classicists prefer sociable tests. Today I know and respect xunit testers of both styles (personally I’ve stayed with classic style).

2000년대 들어 xunit 테스팅이 인기가 많아 지면서 몇몇 사람들에게는 고립 테스트의 개념도 재등장했다. 그리고 목 객체와 모킹을 지원하는 프레임워크가 흥했다. 내가 각각 ‘고전적’과 ‘Mockist’ 스타일이라고 부르는 xunit testing의 두 분파들이 생겨났다. 두 스타일의 차이 중 하나는 고전적 진영에서는 통합된 테스트를 선호하는 반면, Mockist들은 고립 단위 테스트를 고집한다는 것이다. 오늘날에는 나는 양쪽 진영의 xunit 테스터들을 알고 존중한다(개인적으로는 고전적 진영에 머물러 있다).

Even a classic tester like myself uses test doubles when there’s an awkward collaboration. They are invaluable to remove non-determinism when talking to remote services. Indeed some classicist xunit testers also argue that any collaboration with external resources, such as a database or filesystem, should use doubles. Partly this is due to non-determinism risk, partly due to speed. While I think this is a useful guideline, I don’t treat using doubles for external resources as an absolute rule. If talking to the resource is stable and fast enough for you then there’s no reason not to do it in your unit tests.

심지어 나 같은 고전적 테스터들도 시스템간 이상한 협업이 있을 때는 테스트 대역을 사용한다. 테스트 대역은 원격 서비스와의 통신에서의 비결정적인 사항들을 제거할 때 아주 중요하다. 실제로 고전적 xunit 테스터들은 데이터베이스나 파일시스템 같은 어떤 외부 자원과의 협업에서도 대역을 사용해야 한다고 말한다. 부분적으로는 비결정적 위험 때문이고, 또 부분적으로는 속도 때문이다. 물론 나는 이것들이 유용한 가이드라인이라고 생각하지만, 외부 자원에 대해 대역을 사용하는 것이 절대적인 규칙이라고 생각하지는 않는다.

Speed (속도)

The common properties of unit tests — small scope, done by the programmer herself, and fast — mean that they can be run very frequently when programming. Indeed this is one of the key characteristics of SelfTestingCode. In this situation programmers run unit tests after any change to the code. I may run unit tests several times a minute, any time I have code that’s worth compiling. I do this because should I accidentally break something, I want to know right away. If I’ve introduced the defect with my last change it’s much easier for me to spot the bug because I don’t have far to look.

단위 테스트의 일반적인 속성들 – 작은 범위, 개발자가 직접 작성할 것, 빠름 – 은 프로그래밍 하는 동안 테스트가 매우 자주 실행될 것을 의미한다. 실제로 SelfTestingCode의 중요한 특징 중 하나이기도 하다. 이런 상황에서 개발자는 어떤 코드의 변경에도 단위 테스트를 실행한다. 나는 내 코드를 컴파일할 만할 때마다 1분에 몇 번 씩 단위 테스트들을 실행하기도 한다. 왜냐하면 만약 내가 (코드의) 어떤 부분을 나도 모르게 깨트렸다면, 그 즉시 알기 위해서이다. 결함을 발견했을 때는 내가 방금 작성한 코드로부터 먼 곳까지 살펴볼 필요가 없기 때문에 버그를 발견하기도 훨씬 쉽다.

When you run unit tests so frequently, you may not run all the unit tests. Usually you only need to run those tests that are operating over the part of the code you’re currently working on. As usual, you trade off the depth of testing with how long it takes to run the test suite. I’ll call this suite the compile suite, since it’s what I run whenever I think of compiling – even in an interpreted language like Ruby.

당신이 단위 테스를 매우 자주 실행한다면, 모든 단위 테스르를 전부 실행할 필요는 없을 것이다. 보통은 지금 작업 중인 코드와 관련하여 작동하는 테스트들만 실행하면 된다. 일반적으로는 테스트의 깊이와 테스트 모음을 실행하는데 걸리는 시간 사이에 트레이드 오프가 있다. 이 작업은 컴파일 할 때 마다 실행하는 작업이기 때문에 – 루비 같은 인터프리터 언어로 작업 중이라고 해도 – 나는 이 테스트 모음을 컴파일 모음이라고 부를 것이다.

If you are using Continuous Integration you should run a test suite as part of it. It’s common for this suite, which I call the commit suite, to include all the unit tests. It may also include a few BroadStackTests. As a programmer you should run this commit suite several times a day, certainly before any shared commit to version control, but also at any other time you have the opportunity – when you take a break, or have to go to a meeting. The faster the commit suite is, the more often you can run it. [3]

만약 당신이 지속적 통합을 사용 중이라면, 테스트 모음을 지속적 통합의 부분으로서 실행해야 한다. 내가 커밋 모음이라고 부르는 이 모음은 흔히 모든 단위 테스트들을 포함한다. 어쩌면 약간의 BroadStackTests를 포함할 수도 있다. 개발자는 버전 컨트롤에 커밋을 공유하기 전 뿐만 아니라 기회가 있을 때마다 – 쉴 때, 회의에 참여할 때 – 확실히, 하루에 몇 번 씩은 이 커밋 모음을 실행해야 한다. 커밋 모음이 빠를 수록 더 자주 실행할 수 있다.

Different people have different standards for the speed of unit tests and of their test suites. David Heinemeier Hansson is happy with a compile suite that takes a few seconds and a commit suite that takes a few minutes. Gary Bernhardt finds that unbearably slow, insisting on a compile suite of around 300ms and Dan Bodart doesn’t want his commit suite to be more than ten seconds

단위 테스트의 속도나 테스트 모음에 대해서는 사람들마다 다른 기준을 가지고 있다. David Heinemeier Hansson은 몇 초짜리 컴파일 모음과 몇 분짜리 커밋 모음에 만족해하고 있다. Gary Bernhardt는 참을 수 없을 정도로 느린, 300ms짜리 컴파일 모음을 고집하고, Dan Bodart는 자기의 커밋 모음이 10분이 넘지 않아야 한다고 생각한다.

I don’t think there’s an absolute answer here. Personally I don’t notice a difference between a compile suite that’s sub-second or a few seconds. I like Kent Beck’s rule of thumb that the commit suite should run in no more than ten minutes. But the real point is that your test suites should run fast enough that you’re not discouraged from running them frequently enough. And frequently enough is so that when they detect a bug there’s a sufficiently small amount of work to look through that you can find it quickly.

여기에 정답이 있다고 생각하지는 않는다. 나는 개인적으로 1초 이하나 몇 초짜리 컴파일 모음 사이의 차이를 알아차리지 못한다. 그리고 커밋 모음은 10분을 넘지 말아야 한다는 Kent Beck의 엄지 규칙을 좋아한다. 하지만 중요한 점은 당신이 그 테스트 모음을 자주 실행하는데 방해되지 않을 만큼은 빠르게 돌아야 한다는 것이다. 테스트 모음을 충분히 자주 실행해야 하는 이유는 테스트가 버그를 발견했을 때 충분히 빠르게 살펴볼 만큼 일의 양을 적게 만들기 위해서이다.


Notes

1: I say “these days” because this is certainly something that has changed due to XP. In the turn-of-the-century debates, XPers were strongly criticized for this as the common view was that programmers should never test their own code. Some shops had specialized unit testers whose entire job would be to write unit tests for code written earlier by developers. The reasons for this included: people having a conceptual blindness to testing their own code, programmers not being good testers, and it was good to have a adversarial relationship between developers and testers. The XPer view was that programmers could learn to be effective testers, at least at the unit level, and that if you involved a separate group the feedback loop that tests gave you would be hopelessly slow. Xunit played an essential role here, it was designed specifically to minimize the friction for programmers writing tests.

“요즈음”이라고 말했는데, 이것이 명확하게 XP 때문에 바뀌어 가고 있는 무언가이기 때문이다. 세기의 논쟁에서, XPer들은 그들이 가지고 있는 프로그래머들이 절대 자신의 코드를 테스트 해서는 안된다는 일반적인 견해를 강력하게 비판해왔다. 어떤 회사는 개발자들이 만든 코드에 단위 테스트를 작성하려고 하는 전문 단위 테스터들을 가지고 있다. 그 이유는: 사람들은 자기 코드를 테스트하는 것에 대해 개념적 실명 상태에 있는 것, 좋은 테스터가 아닌 개발자들, 개발자와 테스터 사이에 적대적 관계를 가지는 것은 좋은 것이었던 분위기. XPer의 견해는 개발자들이 최소한 단위 수준에서는 효과적인 테스터가 되는 법을 배울 수 있었고, (XP가 아닌)별도의 그룹에 참여했다면 테스트가 너에게 주는 피드백 루프가 절망적으로 느릴 것이다. Xunit은 여기서 필수적인 역할을 하고 있고, 개발자가 테스트를 작성할 때 마찰을 최소화하는데 특별히 디자인되어 있다.

2: Jay Fields came up with the terms ”solitary” and “sociable”

Jay Fields의 저서의 용어 “고립”과 “통합”

3: If you have tests that are useful, but take longer than you want the commit suite to run, then you should build a DeploymentPipeline and put the slower tests in a later stage of the pipeline.

유용한 테스트들을 가지고 있지만 생각보다 커밋 모음이 느리게 동작한다면, DeploymentPipeline을 구축하고 느린 테스트들을 파이프라인의 마지막 단계에 놓아야 한다.


Revisions (수정 사항)

Updated on Oct 24 2014 to include a mention of Field’s sociable/solitary vocabulary.

2014년 10월 24일에 Field의 통합/고립 어휘 사용 언급을 포함함.

Updated on March 9 2017 to make the solitary/sociable terms the primary way of describing the distinction and removing the use of the term “collaborator isolation” (due to confusion with isolating test fixture changes from each other).

2017년 3월 9일에 “협동자 고립”이라는 용어 사용을 제거하고, 고립/통합을 구분하고 묘사하는 주된 방법을 사용했다.