>  기사  >  백엔드 개발  >  왜 단위 테스트인가? 테스트를 수행하는 방법?

왜 단위 테스트인가? 테스트를 수행하는 방법?

青灯夜游
青灯夜游앞으로
2022-10-10 19:19:392261검색

왜 단위 테스트인가? 테스트를 수행하는 방법?

다음은 제가 이 주제에 대해 이야기하는 비디오 링크입니다.

비디오가 마음에 들지 않으면 여기에 긴 버전이 있습니다.

Software

소프트웨어는 변경될 수 있습니다. 이것이 바로 "소프트웨어"라고 불리는 이유입니다. 하드웨어보다 가소성이 더 강합니다. 훌륭한 엔지니어 팀은 회사의 놀라운 자산이 되어야 하며 비즈니스가 성장함에 따라 지속적으로 가치를 추가하는 시스템을 작성해야 합니다.

그렇다면 우리는 왜 그렇게 서툴까요? 완전히 실패했다는 말을 들어본 프로젝트가 몇 개나 되나요? 아니면 "레거시"가 되어 완전히 다시 작성해야 합니다(다시 작성도 일반적으로 실패합니다!)

소프트웨어 시스템은 어떻게 "실패"합니까? 정확하기 전에는 수정할 수 없나요? 이것이 우리의 약속입니다!

많은 사람들이 Go에서 시스템을 구축하기로 선택하는 이유는 사람들이 더 쉽게 읽을 수 있기를 바라는 많은 선택이 가능했기 때문입니다. [관련 권장 사항: Go 비디오 튜토리얼]

  • 이전 Scala 경력과 비교하면목을 매고 싶은 충동이 생긴다고 설명합니다, Go에는 25개의 키워드만 있고 많은을 표준에서 다운로드할 수 있습니다. 도서관 및 다른 작은 도서관에 구축된 시스템입니다. Go를 사용하면 코드를 작성하고 6개월 후에 다시 살펴볼 수 있으며 여전히 의미가 있다는 것이 비전입니다.

  • 테스트, 벤치마킹, 의미 분석 및 로딩을 위한 도구는 대부분의 대안에 비해 최고 수준입니다.

  • 훌륭한 표준 라이브러리.

  • 엄격한 피드백 루프로 인해 컴파일이 매우 빨라집니다.

  • Go는 이전 버전과의 호환성을 보장합니다. 앞으로 Go에 일반 기능과 기타 기능이 추가될 것으로 보이지만 디자이너들은 5년 전에 작성한 Go 코드도 여전히 빌드될 것이라고 약속했습니다. 저는 프로젝트를 Scala 2.8에서 2.10으로 업그레이드하는 데 몇 주를 보냈습니다.

이러한 훌륭한 특성에도 불구하고 여전히 나쁜 시스템을 만들 수 있으므로 사용하는 언어가 훌륭하든 그렇지 않든 과거의 소프트웨어 엔지니어링을 되돌아보고 배운 교훈을 이해해야 합니다.

1974년, [Manny Lehman](https://en.wikipedia.org/wiki/Manny_Lehman...)이라는 똑똑한 소프트웨어 엔지니어가 Lehman의 소프트웨어 진화 법칙을 썼습니다.

이 법칙은 새로운 발전을 주도하는 세력과 진보를 방해하는 세력 사이의 균형을 설명합니다.

우리가 개발하는 시스템이 레거시가 되어 계속해서 다시 작성되는 것을 원하지 않는다면 이러한 힘을 이해하는 데 집중해야 합니다.

지속적인 변화의 법칙

실생활에서 사용되는 소프트웨어 시스템은 끊임없이 변화해야 합니다. 그렇지 않으면 일반 환경에 의해 제거될 것입니다.

분명히 시스템반드시

변화해야 합니다. 그렇지 않으면 그럴 것입니다. 점점 쓸모없어지는데 왜 이런 상황은 종종 무시되는 걸까요?

많은 개발팀이 지정된 날짜까지 프로젝트를 제공하면 보너스를 받고 다음 프로젝트로 넘어갈 것이기 때문입니다. 소프트웨어가 "운이 좋다"면 적어도 어떤 형태로든 다른 그룹의 사람들에게 넘겨져 유지 관리가 이루어지지만 계속해서 반복 작업을 수행하지는 않을 것입니다.

사람들은 일반적으로 시스템 지속성 개발에 집중하기보다는 "빠른 전달"에 도움이 되는 프레임워크 선택에 관심을 갖습니다.

훌륭한 소프트웨어 엔지니어라도 시스템의 향후 요구 사항을 이해하지 못해 희생양이 될 수 있습니다. 귀하의 비즈니스가 변화함에 따라 귀하가 작성한 훌륭한 코드는 더 이상 관련성이 없을 수 있습니다.

리먼은 우리에게 숙고할 가치가 있는 또 다른 규칙을 제시했기 때문에 1970년대에 큰 성공을 거두었습니다.

복잡성 증가의 법칙

시스템이 발전함에 따라 시스템 복잡성의 증가를 줄이기 위한 조치를 취하지 않으면 시스템의 복잡성은 계속 증가할 것입니다.

지금 그가 말하려는 내용은 다음과 같습니다. 우리는 소프트웨어 팀이 순수한 기능 공장이 되어 단순히 시스템이 장기적으로 계속 작동할 수 있도록 점점 더 많은 기능을 소프트웨어에 집중하도록 놔둘 수는 없습니다.

지식 환경이 변화함에 따라 우리는 반드시

시스템의 복잡성을 계속 관리해야 합니다.

리팩토링

소프트웨어 개발은 ​​

  • 개발자 권한 부여

  • 일반적으로 "좋은" 코드와 같은

    다양한

    방식으로 소프트웨어의 유연성을 유지할 수 있습니다. 합리적인 코드 분리 등에 주의하세요.
  • 의사소통 능력
  • 아키텍처
  • 관찰 가능성
  • 배포 가능성
  • 자동화된 테스트
  • 폐쇄 루프

그러겠습니다. 리팩토링에 중점을 둡니다. 프로그래밍 첫날 개발자들이 흔히 하는 말은 "이것을 리팩터링해야 합니다"라는 것입니다.

이 문장은 and? 리팩토링은 코드 작성과 어떻게 다릅니까? 🎜

나와 다른 많은 사람들이 우리가 리팩토링하고 있다고 생각했지만 우리가 틀렸다는 것을 알고 있습니다.

Martin Fowler는 사람들이 어떻게 실수를 하는지 설명합니다

그러나 "리팩토링"은 부적절한 장소에서 자주 사용됩니다. 누군가가 리팩토링하는 동안 며칠 동안 다운된 시스템에 대해 논의한다면 그 사람이 리팩토링을 하고 있지 않다는 것을 확신할 수 있습니다.

그게 뭐야?

Factoring

학교에서 수학을 공부할 때 아마도 인수분해에 대해 배웠을 것입니다. 다음은 매우 간단한 예입니다.

1/2 + 1/4 계산1/2 + 1/4

为此,将分母 分解,将表达式转换为

2/4 + 1/4 你可以把它变成 3/4.

我们可以从中吸取一些重要的教训。当我们 分解表达式 时,我们没有改变表达式的含义。两者都等于 3/4,但我们通过将 1/2 变为 2/4 后,我们的工作变得更容易了;它更适合我们的「领域」。

当你重构代码时,你应该在「符合」你当前系统需求的情况下,尝试找到一个方法来使你的代码更容易理解。关键是你不应该改变代码原有的行为.

Go 的一个例子

下面这个方法是用特定的 language 问候 name

func Hello(name, language string) string {
    if language == "es" {
        return "Hola, " + name
    }

    if language == "fr" {

        return "Bonjour, " + name

    }

    // 想象一下更多的语言

    return "Hello, " + name

}

如果有几十个 if 语句会让人感觉不舒服,而且我们还要重复的使用特定的 language 去伴随着 , 问候 name。因此,我们来重构代码。

func Hello(name, language string) string {
      return fmt.Sprintf(
          "%s, %s",
          greeting(language),
          name,
      )
}

var greetings = map[string]string {
  es: "Hola",
  fr: "Bonjour",
  //等等...
}

func greeting(language string) string {
  greeting, exists := greetings[language]

  if exists {
     return greeting
  }

  return "Hello"
}

实际上,这个重构的本质并不重要,重要的是我们没有改变代码的行为。

当重构时,你可以做任何你喜欢的事情,添加接口,新类型,函数,方法等等。唯一的规则是你不能改变代码的行为。

重构代码时不要改变功能

这非常重要。如果你重构时改变功能,你相当于同时在做 件事。作为软件工程师,我们应该学习把系统分成不同的文件/包/功能/等等,因为我们知道试图理解一大块东西是困难的。

我们不要一次想很多事情,因为那会使我们犯错误。我目睹了许多重构工作的失败,因为开发人员贪多嚼不烂。

当我在数学课上用笔和纸做因式分解时,我必须手动检查我是否改变了头脑中表达式的意思。当我们重构代码时,尤其是在一个重要的系统上,我们如何知道我们是否改变了功能?

那些选择不编写测试的人通常依赖于手动测试。除非是一个小项目,要不然这将是一个巨大的时间消耗,并且从长远来看不利于系统将来的扩展。

为了安全地重构,您需要单元测试因为它提供了

  • 可以在不担心功能改变的情况下重构代码

  • 有助于开发人员编写关于系统应该如何运行的文档

  • 比手工测试更快更可靠的反馈

Go 的一个例子

我们有一个 Hello 方法的单元测试是这样的:

func TestHello(t *testing.T) {

    got := Hello("Chris", es)

    want := "Hola, Chris"

    if got != want {

        t.Errorf("got %q want %q", got, want)

    }

}

在命令行中,我们可以运行 go test

이렇게 하려면 분모를

인수분해하고 표현식을
  • 2/4 + 1 /4로 변환합니다. 3/4로 변경할 수 있습니다.

    이로부터 몇 가지 중요한 교훈을 얻을 수 있습니다.
  • 표현식을 분해
  • 할 때 우리는

    표현의 의미를 바꾸지 않습니다

    . 둘 다 3/4와 동일하지만 1/22/4로 변경하면 작업이 더 쉬워집니다. "필드".
  • 코드를 리팩터링할 때 현재 시스템 요구 사항에 "적합"하면서 코드를 더 쉽게 이해할 수 있는 방법을 찾으려고 노력해야 합니다. 핵심은

    코드의 원래 동작을 변경하면 안 됩니다

    .
Go의 예

다음 방법은 특정 언어를 사용합니다. 인사말 이름 <p>rrreee</p> 수십 개의 <code>if 문이 있고 와 함께 특정 <code>언어를 반복적으로 사용해야 한다면 불편할 것입니다.는 이름에게 인사합니다. 그럼 코드를 리팩터링해 보겠습니다.

rrreee 사실 이 리팩토링의 성격은 중요하지 않습니다. 중요한 것은 코드의 동작을 변경하지 않았다는 것입니다.

리팩토링할 때 원하는 대로 무엇이든 할 수 있고 인터페이스, 새로운 유형, 함수, 메서드 등을 추가할 수 있습니다. 유일한 규칙은 코드의 동작을 변경할 수 없다는 것입니다.

코드를 리팩토링할 때 기능을 변경하지 마세요

이것은 매우 중요합니다. 리팩토링 시 기능을 변경하면 두 가지

작업을 동시에 수행하게 됩니다. 소프트웨어 엔지니어로서 우리는 시스템을 서로 다른 파일/패키지/기능 등으로 분리하는 방법을 배워야 합니다. 왜냐하면 우리는 무언가의 큰 덩어리를 이해하려고 노력하는 것이 어렵다는 것을 알고 있기 때문입니다.

한 번에 많은 것을 생각하면 실수를 하게 되기 때문입니다. 나는 개발자들이 자신이 할 수 있는 것보다 더 많은 것을 물어뜯기 때문에 많은 리팩토링 노력이 실패하는 것을 목격했습니다.

수학시간에 펜과 종이로 인수분해를 할 때, 머릿속에서 표현의 의미가 바뀌었는지 수동으로 확인해야 해요. 특히 중요한 시스템에서 코드를 리팩터링할 때 기능이 변경되었는지 어떻게 알 수 있나요?

테스트를 작성하지 않기로 선택한 사람들은 종종 수동 테스트에 의존합니다. 소규모 프로젝트가 아닌 한 이는 엄청난 시간이 소요될 것이며 장기적으로 향후 시스템 확장에 도움이 되지 않을 것입니다.

안전하게 리팩터링하려면 단위 테스트가 필요합니다.

제공되는 대로

코드는 기능 변경에 대한 걱정 없이 리팩터링될 수 있습니다. 🎜🎜🎜🎜 개발자가 시스템 작동 방식에 대한 코드를 작성하는 데 도움이 됩니다. 문서 🎜🎜🎜🎜 더 빠르고 안정적입니다. 수동 테스트보다 피드백 🎜🎜🎜

Go의 예

🎜다음과 같은 Hello 메서드에 대한 단위 테스트가 있습니다. 🎜rrreee 🎜명령줄에서 다음을 실행할 수 있습니다. code>테스트로 이동
하여 리팩토링 작업이 원본 프로그램 실행에 영향을 미치는지 여부에 대한 즉각적인 피드백을 받으세요. 실제로 편집기/IDE에서 테스트를 실행하는 방법을 배우는 것이 더 좋습니다. 🎜🎜프로그램의 실행 상태를 얻으려는 경우🎜🎜🎜🎜소규모 리팩토링🎜🎜🎜🎜테스트 실행🎜🎜🎜🎜반복🎜🎜🎜🎜모든 것이 매우 긴밀한 피드백 루프에 포함되어 있어 실수가 발생하지 않습니다. 🎜🎜프로젝트에서 모든 주요 동작은 단위 테스트를 거쳐 1초 이내에 피드백이 제공됩니다. 이는 필요할 때 대담한 리팩토링을 수행할 수 있는 매우 강력한 안전망입니다. 이는 Lehman이 설명하는 증가하는 복잡성을 관리하는 데 도움이 됩니다. 🎜🎜🎜단위 테스트는 너무 훌륭합니다. 왜 테스트를 작성할 때 가끔 저항에 직면하시나요? 🎜🎜🎜저와 같은 사람들은 단위 테스트가 자신 있게 리팩토링을 계속할 수 있도록 보장하기 때문에 시스템의 장기적인 상태에 중요하다고 말합니다. 🎜🎜반면에 어떤 사람들은 단위 테스트가 실제로 리팩토링을 🎜방해🎜한다고 말합니다. 🎜🎜리팩토링할 때 테스트를 얼마나 자주 변경해야 하는지 자문해 보세요. 나는 지난 몇 년간 테스트 적용 범위가 매우 높은 많은 프로젝트에 참여해 왔지만 엔지니어들은 테스트를 변경하는 것이 힘들 것이라고 생각하여 리팩토링을 꺼렸습니다. 🎜🎜이것은 우리의 약속에 어긋납니다! 🎜🎜🎜이게 왜죠? 🎜🎜🎜정사각형을 그리라는 요청을 받았다고 가정해 보겠습니다. 가장 좋은 방법은 두 개의 삼각형을 서로 붙이는 것입니다. 🎜🎜🎜🎜🎜두 개의 직각 삼각형이 정사각형을 만듭니다

정사각형 주위에 단위 테스트를 작성하여 양쪽이 동일한지 확인한 다음 삼각형 주위에 몇 가지 테스트를 작성합니다. 우리는 삼각형이 올바르게 렌더링되었는지 확인하기 위해 각도의 합이 180도라고 주장하고 두 가지 테스트를 수행하여 확인합니다. 테스트 범위는 매우 중요하며 이러한 테스트를 작성하는 것은 매우 쉽습니다.

몇 주 후 변경된 법률이 우리 시스템에 영향을 미치고 새로운 개발자가 몇 가지 사항을 변경했습니다. 이제 그녀는 두 개의 삼각형보다는 두 개의 직사각형으로 정사각형을 만드는 것이 더 나을 것이라고 생각합니다.

두 개의 직사각형이 정사각형을 만듭니다

그는 이 리팩토링을 시도했고 실패한 테스트에서 몇 가지 힌트를 얻었습니다. 그가 정말로 코드의 중요한 기능을 깨뜨렸나요? 이제 그녀는 이 삼각형의 테스트에 대해 더 깊이 파고들어 그 안에서 실제로 무슨 일이 일어나고 있는지 이해하려고 노력해야 합니다.

정사각형이 삼각형으로 구성되어 있다는 것은 실제로 중요하지 않습니다 . 하지만 우리 테스트에서는 실수로 구현 세부 사항의 중요성을 높였습니다 .

구현 세부 사항이 아닌 테스트 기능

사람들이 단위 테스트에 대해 불평하는 것을 들으면 대개 테스트의 추상화 수준이 잘못되었기 때문입니다. 그들은 모두 구현 세부 사항을 테스트하고, 공동 작업자의 코드를 강박적으로 관찰하며, 많은 조롱을 합니다.

저는 이 문제가 단위 테스트에 대한 오해와 측정항목(테스트 적용 범위) 추구 때문에 발생한다고 생각합니다.

기능 테스트만 이야기한다면 시스템/블랙박스 테스트만 작성하면 되는 것 아닌가요? 이러한 유형의 테스트는 주요 사용자 여정을 검증하는 데 많은 가치가 있지만 작성 비용이 많이 들고 실행 속도가 느린 경우가 많습니다. 이런 이유로 피드백 루프가 느리기 때문에 리팩토링에는 별로 도움이 되지 않습니다. 게다가 블랙박스 테스트는 단위 테스트에 비해 근본적인 문제를 해결하는 데 큰 도움이 되지 않습니다.

그렇다면 적절한 추상화 수준은 이란 무엇입니까?

효과적인 단위 테스트를 작성하는 것은 설계 문제입니다.

테스트에 대해서는 잠시 잊어버리십시오. 도메인의 핵심 개념을 중심으로 시스템에 독립적이고 분리된 "단위"를 포함시키는 것이 좋습니다.

저는 이러한 유닛을 다른 벽돌과 결합하여 더 큰 시스템을 구축할 수 있는 일관된 API를 갖춘 단순한 레고 벽돌로 생각하고 싶습니다. 이러한 API 내부에는 필요에 따라 작동하도록 협력하는 많은 항목(유형, 기능 등)이 있을 수 있습니다.
예를 들어 Go를 사용하여 뱅킹 시스템을 개발하는 경우 "계정" 패키지가 있어야 합니다. 구현 세부 정보가 유출되지 않고 통합이 쉬운 API를 제공합니다.

단위가 이러한 속성을 준수하는 경우 공개 API에 대한 단위 테스트를 작성할 수 있습니다. 정의에 따르면 이러한 테스트는 유용한 기능만 테스트할 수 있습니다. 이러한 단위를 사용하면 필요할 때마다 자유롭게 리팩터링할 수 있으며 대부분의 경우 테스트가 방해가 되지 않습니다.

이게 단위 테스트인가요?

. 단위 테스트는 내가 "단위"라고 설명하는 것에 대한 것입니다. 그들은 절대로 하나의 클래스/함수/무엇이든만을 대상으로 합니다.

이러한 개념 결합

우리는 이미

  • 리팩토링

  • 유닛 테스트

  • 유닛 디자인

에 대해 이야기했습니다. 각각 다른.

Refactoring

  • 단위 테스트를 위한 신호를 제공하세요. 수동으로 확인해야 한다면 더 많은 테스트가 필요합니다. 테스트가 실패하면 테스트가 잘못된 추상화 수준에 있는 것입니다(또는 가치가 없으므로 제거해야 함).

  • 유닛 내 및 유닛 간의 복잡성을 처리하는 데 도움이 됩니다.

단위 테스트

  • 는 리팩토링을 위한 안전 보호 기능을 제공합니다.

  • 우리 장치의 기능을 확인하고 문서화하세요.

(잘 설계된) 단위

  • 작성하기 쉽고 의미있는 단위 테스트입니다.

  • 리팩터링이 쉽습니다.

복잡성을 관리하고 시스템 확장성을 유지하기 위해 지속적으로 코드를 리팩토링하는 데 도움이 되는 프로세스가 있습니까?

왜 테스트 주도 개발(TDD)

어떤 사람들은 리먼의 아이디어에 대해 혼란스러워할 수도 있습니다. 소프트웨어를 지속적으로 변경하는 것은 과도한 엔지니어링으로 이어지며 사전에 "완벽한" 확장 가능한 시스템을 만들려고 많은 시간을 낭비하게 되지만 아무것도 달성하지 못합니다.

소프트웨어가 좋지 않았던 시절에는 분석가 팀이 요구 사항 문서를 작성하는 데 6개월을 소비했고, 설계자 팀이 설계에 6개월을 소비했으며, 몇 년 후에는 전체 프로젝트가 실패했습니다.

예전은 좋지 않았지만 여전히 그렇습니다!

애자일 개발은 소프트웨어 설계에 대한 피드백을 신속하게 얻을 수 있도록 반복적으로 작업하고 작게 시작하여 지속적으로 소프트웨어를 개선해야 한다는 점을 가르쳐줍니다. 소프트웨어는 실제 사용자와 함께 작동합니다. TDD는 이러한 접근 방식을 시행합니다.

TDD는 지속적인 리팩토링과 반복 제공이라는 개발 접근 방식을 장려하여 Lehman이 언급한 법률과 역사적으로 배우기 어려운 기타 교훈을 다룹니다.

작은 단계

  • 작은 기능에 대한 작은 테스트 작성

  • 명백한 오류로 인해 테스트가 실패하는지 확인(빨간색)

  • 테스트를 통과하기 위한 최소 코드 작성(녹색)

  • Refactor

  • 위의 단계를 반복하세요

숙달됨에 따라 이것이 자연스러운 업무 방식이 되어 작업 효율성이 점점 더 높아질 것입니다

작은 테스트 유닛은 전체 테스트를 완료하는 데 그리 오랜 시간이 걸리지 않습니다. 왜냐하면 프로그램이 지속적으로 "녹색"이 아닌 상태에 있다는 것을 알게 된다면 이는 약간의 문제가 있을 수 있다는 신호이기 때문입니다.

이러한 테스트 피드백을 통해 일부 소규모 애플리케이션 기능의 안정성을 쉽게 확인할 수 있습니다.

만족스러운 엔딩

  • 소프트웨어의 장점은 필요에 따라 변경할 수 있다는 점입니다. 시간이 지남에 따라 예측할 수 없는 이유로 인해 대부분의 소프트웨어는 필요에 따라 해당 변경을 수행해야 하지만 처음에는 과로하거나 과도하게 설계하지 마십시오. 미래를 예측하기가 너무 어렵기 때문입니다.

  • 위의 요구 사항을 충족하려면 소프트웨어의 확장성을 유지해야 합니다. 그렇지 않으면 소프트웨어를 리팩토링하고 업그레이드해야 할 때 상황이 매우 나빠질 것입니다.

  • 좋은 단위 테스트는 프로젝트를 빠르고 즐겁게 리팩토링하는 데 도움이 될 수 있습니다.

  • 좋은 단위 테스트를 작성하는 것은 디자인 문제입니다. 전체 프로젝트의 테스트를 성공적으로 완료하기 위해 레고 블록을 조립하는 것처럼 각 단위 테스트가 흥미롭게 통합될 수 있도록 코드를 구조화하기 위해 신중하게 생각해야 합니다.

  • 테스트 중심 개발(TDD Test-Driven Development)은 잘 설계된 소프트웨어를 반복적으로 개발하는 데 도움을 주고 이를 기술 지원으로 사용하는 것이 향후 작업에 큰 도움이 될 것입니다.

원본 주소 : https://quii.gitbook.io/learn-go-with-tests/meta/why

번역 주소 : https://learnku.com/go/t/34095

더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 비디오를 방문하세요! !

위 내용은 왜 단위 테스트인가? 테스트를 수행하는 방법?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제