단위 테스트

코드를 변경하거나 추가한 후에는 기존 단위 테스트를 실행하고 더 많이 작성해 보는 것이 좋습니다. 모든 테스트는 압축되지 않은 버전의 코드에서 실행됩니다.

단위 테스트에는 JS 테스트와 블록 생성기 테스트의 두 가지 세트가 있습니다.

JS 테스트

JS 테스트는 Blockly의 핵심에서 내부 자바스크립트 함수의 작동을 확인합니다. Mocha를 사용하여 단위 테스트를 실행하고, Sinon을 사용하여 종속 항목을 스텁 처리하며, Chai를 사용하여 코드에 대한 어설션을 만듭니다.

테스트 실행

블록별 샘플과 블록리 샘플 모두에서 npm run test는 단위 테스트를 실행합니다. 블록으로는 린트 작업, 컴파일과 같은 다른 테스트도 실행됩니다. 브라우저에서 tests/mocha/index.html를 열어 모든 Mocha 테스트를 대화형으로 실행할 수도 있습니다.

쓰기 테스트

Mocha TDD 인터페이스를 사용하여 테스트를 실행합니다. 테스트는 추가 하위 모음 또는 테스트를 모두 포함할 수 있는 도구 모음으로 구성됩니다. 일반적으로 Blockly의 각 구성요소 (예: toolbox 또는 workspace)에는 하나 이상의 도구 모음이 포함된 자체 테스트 파일이 있습니다. 각 도구 모음에는 도구 모음의 각 테스트 전후에 각각 호출되는 setupteardown 메서드가 있을 수 있습니다.

테스트 도우미

테스트를 작성할 때 유용할 수 있는 Blockly 전용 도우미 함수가 다양하게 있습니다. coreblockly-samples에서 찾을 수 있습니다.

도우미 함수에는 테스트 전후에 호출되어야 하는 필수sharedTestSetupsharedTestTeardown가 포함됩니다 (요구사항 섹션 참고).

sharedTestSetup:
  • 사이논 가짜 타이머를 설정합니다 (일부 테스트에서는 this.clock.runAll를 사용해야 함).
  • Stubs Blockly.Events.fire가 즉시 실행됩니다 (구성 가능).
  • defineBlocksWithJsonArray를 통해 정의된 blockType의 자동 정리를 설정합니다.
  • this 컨텍스트에서 액세스 가능한 몇 가지 속성을 선언합니다.
    • this.clock (복원하면 안 됨, 그렇지 않으면 sharedTestTeardown에서 문제가 발생함)
    • this.eventsFireStub
    • this.sharedCleanup (addMessageToCleanupaddBlockTypeToCleanup와 함께 사용) (참고: defineBlocksWithJsonArray를 사용하여 블록을 정의한 경우 addBlockTypeToCleanup를 사용할 필요가 없음)

함수에는 설정을 구성하는 options 매개변수(선택사항)가 하나 있습니다. 현재는 Blockly.Events.fire를 스텁 처리하여 즉시 실행할지 여부를 결정하는 데만 사용됩니다 (기본적으로 스텁 처리됨).

sharedTestTeardown:
  • 작업공간 this.workspace를 삭제합니다 (정의된 위치에 따라 다름, 자세한 내용은 테스트 요구사항 섹션 참고).
  • 모든 스텁을 복원합니다.
  • defineBlocksWithJsonArrayaddBlockTypeToCleanup를 통해 추가된 모든 블록 유형을 정리합니다.
  • addMessageToCleanup를 통해 추가된 모든 메시지를 정리합니다.

테스트 요구사항

  • 각 테스트는 sharedTestSetup.call(this);를 가장 바깥쪽 도구 모음 설정의 첫 번째 줄로, sharedTestTeardown.call(this);를 파일 가장 바깥쪽 도구 모음 해체 시 마지막 줄로 호출해야 합니다.
  • 일반 도구 상자가 있는 작업공간이 필요한 경우 테스트 index.html에서 사전 설정된 도구 상자 중 하나를 사용할 수 있습니다. 아래에서 예시를 참조하세요.
  • this.workspace를 올바르게 폐기해야 합니다. 대부분의 테스트에서는 가장 바깥쪽 도구 모음에 this.workspace를 정의하고 이를 모든 후속 테스트에 사용하지만, 일부 경우에는 내부 도구 모음에서 정의하거나 다시 정의할 수 있습니다(예: 테스트 중 하나에 원래 설정한 것과 다른 옵션이 있는 작업공간이 필요함). 테스트 종료 시 폐기해야 합니다.
    • 가장 바깥쪽 도구 모음에서 this.workspace를 정의하고 다시 정의하지 않는 경우 추가 작업이 필요하지 않습니다. sharedTestTeardown에 의해 자동으로 삭제됩니다.
    • 내부 도구 모음에서 this.workspace를 처음 정의하는 경우(즉, 가장 바깥쪽 도구 모음에 정의하지 않은 경우) 도구 모음의 해제에서 workspaceTeardown.call(this, this.workspace)를 호출하여 수동으로 this.workspace를 삭제해야 합니다.
    • 가장 바깥쪽 도구 모음에 this.workpace을 정의한 후 내부 테스트 모음에서 다시 정의하는 경우 먼저 workspaceTeardown.call(this, this.workspace) 재정의하기 전에를 호출하여 최상위 도구 모음에 정의된 원래 작업공간을 해체해야 합니다. 또한 이 내부 도구 모음의 해제에서 workspaceTeardown.call(this, this.workspace)를 다시 호출하여 새 값을 수동으로 삭제해야 합니다.

테스트 구조

단위 테스트는 일반적으로 arrange, action, assert.로 요약할 수 있는 설정된 구조를 따릅니다.

  1. Arrange: 환경의 상태와 테스트 중인 동작에 필요한 조건을 설정합니다.
  2. 실행: 테스트 중인 코드를 호출하여 테스트 중인 동작을 트리거합니다.
  3. Assert: 정확성을 확인하기 위해 반환 값 또는 모의 처리된 객체와의 상호작용에 대한 어설션을 만듭니다.

간단한 테스트에서는 정렬할 동작이 없을 수 있으며 어설션에서 테스트 중인 코드에 대한 호출을 인라인하여 작업 및 어설션 단계를 결합할 수 있습니다. 더 복잡한 사례의 경우 이 3단계를 따르면 테스트의 가독성이 높아집니다.

다음은 테스트 파일의 예입니다 (실제와 다를 수 있음).

suite('Flyout', function() {
  setup(function() {
    sharedTestSetup.call(this);
    this.toolboxXml = document.getElementById('toolbox-simple');
    this.workspace = Blockly.inject('blocklyDiv',
        {
          toolbox: this.toolboxXml
        });
  });

  teardown(function() {
    sharedTestTeardown.call(this);
  });

  suite('simple flyout', function() {
    setup(function() {
      this.flyout = this.workspace.getFlyout();
    });
    test('y is always 0', function() {
      // Act and assert stages combined for simple test case
      chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
    });
    test('x is right of workspace if flyout at right', function() {
      // Arrange
      sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
        viewWidth: 100,
      });
      this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
      this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;

      // Act
      var x = this.flyout.getX();

      // Assert
      chai.assert.equal(x, 100, 'x is right of workspace');
    });
  });
});

이 예에서 참고할 사항은 다음과 같습니다.

  • 도구 모음에는 추가 setupteardown 메서드가 있는 다른 도구 모음이 포함될 수 있습니다.
  • 각 도구 모음과 테스트에는 설명이 포함된 이름이 있습니다.
  • 차이 어설션은 코드에 관한 어설션을 만드는 데 사용됩니다.
    • 테스트가 실패할 경우 표시할 문자열 인수(선택사항)를 제공할 수 있습니다. 이렇게 하면 손상된 테스트를 더 쉽게 디버그할 수 있습니다.
    • 매개변수의 순서는 chai.assert.equal(actualValue, expectedValue, optionalMessage)입니다. actualexpected를 바꾸면 오류 메시지가 의미가 없습니다.
  • Sinon은 실제 코드를 호출하고 싶지 않을 때 메서드를 스텁 처리하는 데 사용됩니다. 이 예에서는 실제 측정항목 함수가 이 테스트와 관련이 없으므로 이 함수를 호출하지 않습니다. 테스트 중인 메서드에서 결과를 사용하는 방식만 고려합니다. Sinon은 테스트 어설션에서 쉽게 확인할 수 있는 미리 준비된 응답을 반환하기 위해 getMetrics 함수를 스텁 처리합니다.
  • 각 모음의 setup 메서드는 모든 테스트에 적용되는 일반 설정만 포함해야 합니다. 특정 동작의 테스트가 특정 조건에 의존하는 경우 해당 조건이 관련 테스트에 명시되어야 합니다.

디버깅 테스트

  • 브라우저에서 테스트를 열고 개발자 도구를 사용하여 중단점을 설정하고 테스트가 예기치 않게 실패하거나 예기치 않게 통과하는지 조사할 수 있습니다.
  • 테스트 또는 도구 모음에서 .only() 또는 .skip()를 설정하여 해당 테스트 집합만 실행하거나 테스트를 건너뜁니다. 예를 들면 다음과 같습니다.

    suite.only('Workspace', function () {
      suite('updateToolbox', function () {
        test('test name', function () {
          // ...
        });
        test.skip('test I don’t care about', function () {
          // ...
        });
      });
    });
    

    코드를 커밋하기 전에 이를 삭제해야 합니다.

블록 생성기 테스트

각 블록에는 자체 단위 테스트가 있습니다. 이 테스트는 블록이 함수보다 의도한 대로 코드를 생성하는지 확인합니다.

  1. Firefox 또는 Safari에서 tests/generators/index.html를 로드합니다. Chrome 및 Opera에는 로컬 'file://' 시스템에서 테스트를 로드하지 못하도록 하는 보안 제한사항이 있습니다 (문제 4102447416).
  2. 드롭다운 메뉴에서 테스트할 시스템의 관련 부분을 선택하고 'Load(로드)'를 클릭합니다. 작업공간에 블록이 표시됩니다.
  3. '자바스크립트'를 클릭합니다.
    생성된 코드를 JavaScript 콘솔에서 복사하여 실행합니다. 출력이 'OK'로 끝나면 테스트가 통과된 것입니다.
  4. 'Python'을 클릭합니다.
    생성된 코드를 Python 인터프리터에서 복사하여 실행합니다. 출력이 'OK'로 끝나면 테스트가 통과된 것입니다.
  5. 'PHP'를 클릭합니다.
    생성된 코드를 PHP 인터프리터에서 복사하여 실행합니다. 출력이 'OK'로 끝나면 테스트가 통과된 것입니다.
  6. 'Lua'를 클릭합니다.
    생성된 코드를 Lua 인터프리터에서 복사하여 실행합니다. 출력이 'OK'로 끝나면 테스트가 통과된 것입니다.
  7. '다트'를 클릭합니다.
    생성된 코드를 Dart 인터프리터에서 복사하여 실행합니다. 출력이 'OK'로 끝나면 테스트가 통과된 것입니다.

블록 생성기 테스트 수정

  1. 브라우저에 tests/generators/index.html를 로드합니다.
  2. 드롭다운 메뉴에서 시스템의 관련 부분을 선택하고 'Load(로드)'를 클릭합니다. 작업공간에 블록이 표시됩니다.
  3. 블록을 변경하거나 추가합니다.
  4. 'XML'을 클릭합니다.
  5. 생성된 XML을 tests/generators/의 적절한 파일에 복사합니다.