본문 바로가기
Flutter

Dart - Test 작성하기(test package)

by 봄석 2019. 12. 13.

Dart - Test 작성하기(test package)

dart의 test package를 사용하여 테스트를 작성하는 방법에 대하여 알아보도록 하겠습니다

 

 

 

목차

Table of Contents

 

 

 

 

test package

https://pub.dev/packages/test#writing-tests

 

test | Dart Package

A full featured library for writing and running Dart tests.

pub.dev

test package는 Dart에서 테스트를 작성하고 실행하는 표준 방법을 제공합니다.

 

 

 

테스트 실행하기

1. 단일 파일 테스트 실행하기

pub run test [test file]

//exsample
pub run test test/first_test.dart

2. 한번에 여러 개의 파일 테스트 실행하기

pub run test [dir path]

//example - 테스트 dir내의 모든 테스트 실행
pub run test test 

3. 크롬 브라우저에서 실행하기

pub run test -p chrome [file path]

//example  - 크롬브라우저에서 test 디렉토리 내의 테스트 모두 실행
pub run test -p chrome test

4. dart vm  실행하기

dart [file path]

//example
dart test/first_test.dart

5. VSC plugin  사용하기

vsc의 Code Runner plugin을 사용하여 단축키로 테스트를 실행 가능합니다. (현재 가장 애용하는 방법입니다)

 

Ctrl + Alt + N(Window)  or  ^ + ⌥  + N (Mac) 을눌러 실행합니다.

Ctrl + Alt + M(Window)  or  ^ + ⌥  + M (Mac) 을눌러 정지합니다.

 

6. debug F5

7. Run

run을 클릭합니다.

 

 

 

 test() , expect() (첫 테스트 작성하기)

void main() {
  test('String.split() splits the string on the delimiter', () {
    var string = 'foo,bar,baz';
    expect(string.split(","), equals(['foo', 'bar', 'baz']));
  });

  test('String.trim() removes surrounding whitespace', () {
    var string = '  foo ';
    expect(string.trim(), equals('foo'));
  });
}

test()를 이용하여 테스트를 작성합니다 

첫 번째 인자로 description을 두 번째 인자로 body()를 전달받습니다.

body안에서 expect assertion을 이용하여  검증합니다.

 

아래는 test 함수의 매개변수들입니다 .  여러 인자로 옵션을 줄 수 있습니다.

@isTest
void test(description, body(),
    {String testOn,
    Timeout timeout,
    skip,
    tags,
    Map<String, dynamic> onPlatform,
    int retry,
    @deprecated bool solo = false}) {
  _declarer.test(description.toString(), body,
      testOn: testOn,
      timeout: timeout,
      skip: skip,
      onPlatform: onPlatform,
      tags: tags,
      retry: retry,
      solo: solo);

  // Force dart2js not to inline this function. We need it to be separate from
  // `main()` in JS stack traces in order to properly determine the line and
  // column where the test was defined. See sdk#26705.
  return;
  return; // ignore: dead_code
}

 

 

 

group

void main() {
  group('String', () {
    test('.split() splits the string on the delimiter', () {
      var string = 'foo,bar,baz';
      expect(string.split(','), equals(['foo', 'bar', "baz"]));
    });

    test('.trim() removes surrounding whitespace', () {
      var string = '  foo ';
      expect(string.trim(), equals('foo'));
    });
  });
  
  
  group('int', () {
    test('.remainder() returns the remainder of division', () {
      expect(11.remainder(3), equals(2));
    });

    test('.toRadixString() returns a hex string', () {
      expect(11.toRadixString(16), equals('b'));
    });
  });
}

group을 이용하여 테스트를 그룹화 할 수 있습니다.

그룹마다 description을 추가할 수 있습니다.

 

 

 

matcher

void main() {
  test('.split() splits the string on the delimiter', () {
    expect('foo,bar,baz', allOf([
      contains('foo'),
      isNot(startsWith('bar')),
      endsWith('baz')
    ]));
  });
}

matcher 패키지늬 matcher를 사용하여 복잡한 검증도 수행할 수 있습니다.

https://pub.dev/documentation/matcher/latest/matcher/matcher-library.html

 

matcher library - Dart API

A matcher which matches if the match argument is zero or negative. const _OrderingMatcher(0, true, true, false, 'a non-positive value', false)

pub.dev

 

 

 

setUp() ,tearDown()

setUp과 tearDown을 이용하여 테스트 간에 코드를 공유할 수 있습니다.

setUp()은 모든 테스트 전에 실행됩니다.

tearDown()은 모든 테스트 수행 이후에 실행됩니다.

void main() {
  HttpServer httpServer;
  Uri url;

  setUp(() async {
    httpServer = await HttpServer.bind('localhost', 0);
    url = Uri.parse('http://${httpServer.address.host}:${httpServer.port}');
  });

  tearDown(()async{
    await httpServer.close(force: true);
    httpServer = null;
    url = null;
  });
  
  ///  ....
  
}

 

 

 

async test (비동기 테스트)

async로 작성된 테스트에서는 await를 사용할 수 있습니다

테스트 러너는 Future 등 비동기 작업이 완료될 때까지 테스트가 완료된 것으로 간주하지 않습니다.

void main() {
  test('new Future.value() returns the value', () async {
    var value = await Future.value(10);
    expect(value, equals(10));
  });
}

 

또한 고급 비 동기화를 위한 유용한 기능과 매칭 기능도 많이 있습니다.

 completion()Future를  테스트하는 데 사용할 수 있습니다

Future가 완료될 때까지 테스트가 완료되지 않도록 하고, 해당 Future값 에 대해 매처를 실행합니다.

 test('new Future.value() returns the value 2222', () {
    expect(Future.value(10), completion(equals(10)));
  });

 

throwsA()는 Future에서 특정 유형의 예외가 발생하도록 합니다.(Future Error)

 test('new Future.error() throws the error', () {
    expect(Future.error('oh no'), throwsA(equals('oh no')));
    expect(Future.error(StateError('bad state')), throwsStateError);
  });

 

expectAsync() 함수는 다른 함수를 감싸고 두 개의 작업이 있습니다. 먼저, 랩핑 된 함수를 테스트합니다.

둘째, 함수가 필수 횟수라고 할 때까지 테스트가 완료되지 않도록 합니다.

  test('Stream.fromIterable() emits the values in the iterable', () {
    var stream = Stream.fromIterable([1, 2, 3]);

    stream.listen(expectAsync1((number) {
      expect(number, inInclusiveRange(1, 3));
    }, count: 3));
  });

 

 

 

Stream Matcher (스트림 매쳐)

test패키지는 비동기 스트림을 처리하기 위한 강력한 매처 모음을 제공합니다.

그것들은 표현력 있고 작곡이 가능하며 스트림에서 방출되는 가치에 대한 복잡한 expect()를 쉽게 작성할 수 있습니다.

 예를 들면 다음과 같습니다.

 

void main() {
  test('process emits status messages', () {
    var stdoutLines = Stream.fromIterable([
      'Ready.',
      'Loading took 150ms.',
      'Succeeded!'
    ]);

    expect(stdoutLines, emitsInOrder([
      'Ready.',
      startsWith('Loading took'),
      emitsAnyOf(['Succeeded!', 'Failed!']),
      emitsDone
    ]));
  });
}

Stream에서 방출되는 값들을 순서대로 처리하는 등의 복잡한 expect 등을 쉽게 처리할 수 있습니다.

 

 

 

스트림 매처는 async패키지 StreamQueue클래스 와도 사용할 수 있으며 ,

이를 통해 소비자에게 이벤트를 푸시하지 않고 스트림에서 이벤트를 요청할 수 있습니다.

매처는 일치하는 이벤트를 사용하지만 Stream 하나의 구독자만 가질 수 있는 일반과 달리

테스트에서 계속 사용할 수 있도록 나머지 큐를 그대로 둡니다.

예를 들면 다음과 같습니다.

test('process emits a WebSocket URL', () async {
    var stdout = StreamQueue(Stream.fromIterable([
      'WebSocket URL:',
      'ws://localhost:1234/',
      'Waiting for connection...'
    ]));

    await expect(stdout, emitsThrough('WebSocket URL:'));

    var url = Uri.parse(await stdout.next);
    expect(url.host, equals('localhost'));

    await expect(stdout, emits('Waiting for connection...'));
  });

 

 

아래와 같은 내장 스트림 matcher를 사용할 수 있습니다.

 

다음과 같은 내장 스트림 매처를 사용할 수 있습니다.

  • emits() 단일 데이터 이벤트와 일치합니다.
  • emitsError() 단일 오류 이벤트와 일치합니다.
  • emitsDone 단일 완료 이벤트와 일치합니다.
  • mayEmit() 일치하지 않아도 내부 매처와 일치하는 경우 이벤트를 사용합니다.
  • mayEmitMultiple()처럼 작동 mayEmit()하지만 가능한 한 여러 번 일치하는 이벤트와 일치합니다.
  • emitsAnyOf() 여러 가능한 일치 중 하나 이상과 일치하는 이벤트를 사용합니다.
  • emitsInOrder() 여러 개의 매처와 일치하는 이벤트를 연속으로 사용합니다.
  • emitsInAnyOrder()처럼 작동 emitsInOrder()하지만 매처를 임의의 순서로 일치시킬 수 있습니다.
  • neverEmits()내부 매처와 일치 하지 않고 완료되는 스트림과 일치합니다 .

new StreamMatcher(). 을 호출하여 사용자 정의 스트림 매처를 정의할 수도 있습니다

 

 

 

테스트 구성

 

skip

테스트 스위트 건너뛰기

@Skip("currently failing (see issue 1234)")

import "package:test/test.dart";

void main() {
  // ...
}

group() 건너뛰기, test() 건너뛰기

void main() {
  group("complicated algorithm tests", () {
    // ...
  }, skip: "the algorithm isn't quite right");

  test("error-checking test", () {
    // ...
  }, skip: "TODO: add error-checking.");
}

 

 

timeout

기본적으로 테스트는 30 초 동안 활동이 없으면 시간이 초과됩니다. 

그러나 이것은 테스트, 그룹 또는 스위트 별로 구성할 수 있습니다. 

테스트 스위트의 제한 시간을 변경하려면 @Timeout파일 맨 위에 주석을 추가하십시오.

@Timeout(const Duration(seconds: 45))

import "package:test/test.dart";

void main() {
  // ...
}

 

절대 시간 초과를 설정하는 것 외에도 을 사용하여 시간 초과를 기본값에 상대적으로 설정할 수 있습니다

 @Timeout.factor. 예를 들어, @Timeout.factor(1.5)시간 제한을 기본값의 1.5 배로 설정합니다. == 45초

 

timeout매개 변수를 사용하여 테스트 및 그룹에 대한 시간 종료를 설정할 수 있습니다.

이 매개 변수는 Timeout주석과 같은 개체를 사용합니다. 예를 들면 다음과 같습니다.

void main() {
  group("slow tests", () {
    // ...

    test("even slower test", () {
      // ...
    }, timeout: new Timeout.factor(2))
  }, timeout: new Timeout(new Duration(minutes: 1)));
}

중첩 시간 초과는 가장 바깥쪽에서 가장 안쪽까지 순서대로 적용됩니다.

즉, "더 느린 테스트"는 그룹의 시간제한에 2를 곱하기 때문에 2 분이 걸립니다.

댓글