Skip to content

Latest commit

 

History

History
462 lines (343 loc) · 13 KB

QuickExamplesAndGroups.md

File metadata and controls

462 lines (343 loc) · 13 KB

Quick Example과 Example그룹으로 구성된 테스트

Quick에는 examplesexample groups를 정의하기 위한 특별한 문법이 있습니다.

XCTest를 사용한 효과적인 테스트 : Arrange, Act, 그리고 Assert 에서, 좋은 테스트 메소드 이름을 붙이는 것이 매우 중요하다는 것을 배웠습니다. — 테스트가 실패했을 때, 테스트 이름은 응용 프로그램 코드를 수정할지, 테스트 코드를 업데이트할지를 결정하는 데 중요한 자료가 됩니다.

Quick examples과 example그룹은 두 가지 용도로 사용됩니다:

  1. 서술적인 테스트 이름을 작성하는 것을 장려합니다.
  2. 테스트 "환경 구축" 단계에서 코드를 매우 단순하게 합니다.

it을 사용한 Examples

it 함수로 정의된 Examples는, 코드가 어떻게 동작하는지를 보여주기 위해 assertions를 사용합니다. 이것들은 XCTest의 테스트 메소드와 같습니다.

it은 example의 이름과 클로저, 두 개의 파라미터가 필요합니다. 아래 example은 Sea.Dolphin 클래스가 어떻게 동작하는지를 지정합니다. 새로운 돌고래는 영리하고 친절해야 합니다:

// Swift

import Quick
import Nimble
import Sea

class DolphinSpec: QuickSpec {
  override func spec() {
    it("is friendly") {
      expect(Dolphin().isFriendly).to(beTruthy())
    }

    it("is smart") {
      expect(Dolphin().isSmart).to(beTruthy())
    }
  }
}
// Objective-C

@import Quick;
@import Nimble;

QuickSpecBegin(DolphinSpec)

it(@"is friendly", ^{
  expect(@([[Dolphin new] isFriendly])).to(beTruthy());
});

it(@"is smart", ^{
  expect(@([[Dolphin new] isSmart])).to(beTruthy());
});

QuickSpecEnd

설명을 사용해서 example이 테스트 중인 내용을 명확하게 하세요. 설명은 어떠한 길이의 아무 문자가 가능하며, 영어 이외로 된 언어나 심지어 이모지를 포함한 모든 문자를 사용할 수 있습니다! ✌️ 😎

describecontext를 사용한 Example그룹

Example 그룹은 example의 논리적 그룹입니다. Example 그룹은 설정(setup)과 분해(teardown) 코드를 공유할 수 있습니다.

서술하는 클래스와 describe를 사용하는 메소드

Dolphin 클래스의 click 메소드의 동작을 지정하기 위해서는 (다시 말해, 메소드의 동작을 테스트하기 위해서는) 몇 가지 it example을 describe 함수를 이용해서 그룹화시킬 수 있습니다. 비슷한 example을 그룹화하면 spec을 더 쉽게 읽을 수 있습니다:

// Swift

import Quick
import Nimble

class DolphinSpec: QuickSpec {
  override func spec() {
    describe("a dolphin") {
      describe("its click") {
        it("is loud") {
          let click = Dolphin().click()
          expect(click.isLoud).to(beTruthy())
        }

        it("has a high frequency") {
          let click = Dolphin().click()
          expect(click.hasHighFrequency).to(beTruthy())
        }
      }
    }
  }
}
// Objective-C

@import Quick;
@import Nimble;

QuickSpecBegin(DolphinSpec)

describe(@"a dolphin", ^{
  describe(@"its click", ^{
    it(@"is loud", ^{
      Click *click = [[Dolphin new] click];
      expect(@(click.isLoud)).to(beTruthy());
    });

    it(@"has a high frequency", ^{
      Click *click = [[Dolphin new] click];
      expect(@(click.hasHighFrequency)).to(beTruthy());
    });
  });
});

QuickSpecEnd

이 두 가지 example이 Xcode에서 실행되면, describeit 함수들의 설명이 표시될 겁니다:

  1. DolphinSpec.a_dolphin_its_click_is_loud
  2. DolphinSpec.a_dolphin_its_click_has_a_high_frequency

다시 말해, 각각의 example이 테스트하고 있는 것이 명확합니다.

beforeEachafterEach를 사용하여 설정 / 해제코드 공유하기

Example groups는 example을 더 명확하게 만들어줄 뿐만 아니라, example 그룹 간에 설정 및 해제 코드를 공유하는 데 유용합니다.

아래 example에서, beforeEach 함수는 그룹에서 각 example 앞에 돌고래와 클릭의 새로운 인스턴스를 생성하는 데 사용되었습니다. 이렇게 하면 모든 example에서 각각은 "신선한" 상태가 되었습니다:

// Swift

import Quick
import Nimble

class DolphinSpec: QuickSpec {
  override func spec() {
    describe("a dolphin") {
      var dolphin: Dolphin!
      beforeEach {
        dolphin = Dolphin()
      }

      describe("its click") {
        var click: Click!
        beforeEach {
          click = dolphin.click()
        }

        it("is loud") {
          expect(click.isLoud).to(beTruthy())
        }

        it("has a high frequency") {
          expect(click.hasHighFrequency).to(beTruthy())
        }
      }
    }
  }
}
// Objective-C

@import Quick;
@import Nimble;

QuickSpecBegin(DolphinSpec)

describe(@"a dolphin", ^{
  __block Dolphin *dolphin = nil;
  beforeEach(^{
      dolphin = [Dolphin new];
  });

  describe(@"its click", ^{
    __block Click *click = nil;
    beforeEach(^{
      click = [dolphin click];
    });

    it(@"is loud", ^{
      expect(@(click.isLoud)).to(beTruthy());
    });

    it(@"has a high frequency", ^{
      expect(@(click.hasHighFrequency)).to(beTruthy());
    });
  });
});

QuickSpecEnd

이러한 공유 설정이 돌고래 예제에서와 큰 차이가 없는 것처럼 보일 수 있지만, 더 복잡한 객체라면 많은 타이핑을 줄여 줄 것입니다!

각각의 example 다음에 코드를 실행하려면 afterEach를 사용하세요.

context를 사용하여 조건부 동작 지정하기

돌고래는 반항위치 결정법(박쥐 등이 초음파를 발사하여 위치를 알아내는 일)을 위해 클릭을 사용합니다. 그들이 특히 흥미로운 것에 접근하면, 그것이 무엇인지 알기 위해 일련의 클릭을 하게 됩니다.

테스트는 click 메소드가 다른 상황에서 다르게 동작하는 것을 보여줄 필요가 있습니다. 일반적으로, 돌고래는 한 번만 클릭합니다. 하지만 돌고래가 어떤 흥미로운 것에 접근하게 된다면, 여러 번 클릭할 것입니다.

이것은 context 함수를 이용해서 표현할 수 있습니다: 일반적인 context와, 돌고래가 흥미로운 것에 가까이 갔을 때의 context입니다:

// Swift

import Quick
import Nimble

class DolphinSpec: QuickSpec {
  override func spec() {
    describe("a dolphin") {
      var dolphin: Dolphin!
      beforeEach { dolphin = Dolphin() }

      describe("its click") {
        context("when the dolphin is not near anything interesting") {
          it("is only emitted once") {
            expect(dolphin.click().count).to(equal(1))
          }
        }

        context("when the dolphin is near something interesting") {
          beforeEach {
            let ship = SunkenShip()
            Jamaica.dolphinCove.add(ship)
            Jamaica.dolphinCove.add(dolphin)
          }

          it("is emitted three times") {
            expect(dolphin.click().count).to(equal(3))
          }
        }
      }
    }
  }
}
// Objective-C

@import Quick;
@import Nimble;

QuickSpecBegin(DolphinSpec)

describe(@"a dolphin", ^{
  __block Dolphin *dolphin = nil;
  beforeEach(^{ dolphin = [Dolphin new]; });

  describe(@"its click", ^{
    context(@"when the dolphin is not near anything interesting", ^{
      it(@"is only emitted once", ^{
        expect(@([[dolphin click] count])).to(equal(@1));
      });
    });

    context(@"when the dolphin is near something interesting", ^{
      beforeEach(^{
        [[Jamaica dolphinCove] add:[SunkenShip new]];
        [[Jamaica dolphinCove] add:dolphin];
      });

      it(@"is emitted three times", ^{
        expect(@([[dolphin click] count])).to(equal(@3));
      });
    });
  });
});

QuickSpecEnd

엄밀히 얘기하면, context 키워드는 describe과 동의어지만, 사려 깊은 사용은 spec을 더 이해하기 쉽게 만들 것입니다.

테스트 가독성: Quick과 XCTest

Effective Tests Using XCTest: Arrange, Act, and Assert에서, 우리는 테스트 당 하나의 조건이 테스트 코드를 구성하는 좋은 방법이라 알아봤습니다. XCTest에서는, 긴 테스트 메소드 이름을 사용합니다:

func testDolphin_click_whenTheDolphinIsNearSomethingInteresting_isEmittedThreeTimes() {
  // ...
}

Quick을 사용하면, 조건을 더 쉽게 읽을 수 있고, 각 example 그룹에 대해 설정을 할 수 있습니다:

describe("a dolphin") {
  describe("its click") {
    context("when the dolphin is near something interesting") {
      it("is emitted three times") {
        // ...
      }
    }
  }
}

일시적으로 Example이나 그룹을 비활성화하기

일시적으로 통과하지 못한 example이나 example 그룹을 비활성화 시킬 수 있습니다. Example의 이름은 테스트 결과와 함께 출력되지만, 비활성화된 것들은 출력되지 않을 것입니다.

example이나 group에 x를 추가함으로써 비활성화 시킬 수 있습니다:

// Swift

xdescribe("its click") {
  // ...none of the code in this closure will be run.
}

xcontext("when the dolphin is not near anything interesting") {
  // ...none of the code in this closure will be run.
}

xit("is only emitted once") {
  // ...none of the code in this closure will be run.
}
// Objective-C

xdescribe(@"its click", ^{
  // ...none of the code in this closure will be run.
});

xcontext(@"when the dolphin is not near anything interesting", ^{
  // ...none of the code in this closure will be run.
});

xit(@"is only emitted once", ^{
  // ...none of the code in this closure will be run.
});

포커스 된 Example의 일정 부분을 임시적 실행하기

때로는 오직 하나나 몇 가지 Example 에만 집중하는 것이 도움이 됩니다. 하나 또는 두 가지의 example만 실행하는 것은 전체를 실행하는 것보다 빠릅니다. fit 함수를 사용해서 하나 또는 두 개만 실행할 수 있습니다. fdescribe 이나 fcontext를 사용해서 역시 Example 그룹에 집중할 수 있습니다:

fit("is loud") {
  // ...only this focused example will be run.
}

it("has a high frequency") {
  // ...this example is not focused, and will not be run.
}

fcontext("when the dolphin is near something interesting") {
  // ...examples in this group are also focused, so they'll be run.
}
fit(@"is loud", {
  // ...only this focused example will be run.
});

it(@"has a high frequency", ^{
  // ...this example is not focused, and will not be run.
});

fcontext(@"when the dolphin is near something interesting", ^{
  // ...examples in this group are also focused, so they'll be run.
});

beforeSuiteafterSuite를 사용하여 전역 설정 / 해제하기

어떤 테스트 설정은 실행되기 전에 일부 example이 실행되어야 합니다. 이럴 때, beforeSuite afterSuite를 사용합니다.

아래의 예제에서는, 모든 example이 실행되기 전에 바다의 모든 생물 데이터베이스가 생성됩니다. 모든 example이 완료되면 데이터베이스는 제거됩니다.

// Swift

import Quick

class DolphinSpec: QuickSpec {
  override func spec() {
    beforeSuite {
      OceanDatabase.createDatabase(name: "test.db")
      OceanDatabase.connectToDatabase(name: "test.db")
    }

    afterSuite {
      OceanDatabase.teardownDatabase(name: "test.db")
    }

    describe("a dolphin") {
      // ...
    }
  }
}
// Objective-C

@import Quick;

QuickSpecBegin(DolphinSpec)

beforeSuite(^{
  [OceanDatabase createDatabase:@"test.db"];
  [OceanDatabase connectToDatabase:@"test.db"];
});

afterSuite(^{
  [OceanDatabase teardownDatabase:@"test.db"];
});

describe(@"a dolphin", ^{
  // ...
});

QuickSpecEnd

beforeSuiteafterSuite를 원하는 만큼 지정할 수 있습니다. 모든 beforeSuite 클로저는 테스트가 실행되기 전에 실행되고, 모든 afterSuite 클로저는 모든 테스트가 끝난 뒤에 실행될 것입니다. 이 클로저들이 어떤 순서로 실행될지는 보장되지 않습니다.

현재 Example의 메타데이터에 액세스하기

현재 실행되고 있는 example에 대한 이름이나, 지금까지 실행되었던 example의 이름을 알고 싶어하는 경우가 있을 수 있습니다. Quick은 beforeEachafterEach 클로저에서 메타데이터에 대한 액세스를 제공합니다.

beforeEach { exampleMetadata in
  println("Example number \(exampleMetadata.exampleIndex) is about to be run.")
}

afterEach { exampleMetadata in
  println("Example number \(exampleMetadata.exampleIndex) has run.")
}
beforeEachWithMetadata(^(ExampleMetadata *exampleMetadata){
  NSLog(@"Example number %l is about to be run.", (long)exampleMetadata.exampleIndex);
});

afterEachWithMetadata(^(ExampleMetadata *exampleMetadata){
  NSLog(@"Example number %l has run.", (long)exampleMetadata.exampleIndex);
});