[비기너 가이드 투 테스팅]

김영진·2023년 4월 10일
0

목적

테스트 공부

내용

테스트란 무엇일까

앱을 코딩할 때 가장 먼저 무엇을 할까요?

테스트합니다! 그리고 제대로 작동하는지 여부를 확인합니다! 버그를 발견하면 수정하고 계속 코딩을 진행하겠죠?

이것이 바로 테스트이지만, 이것이 유일한 방법은 아닙니다!
테스트에는 두 가지 종류가 있습니다!

수동 테스트(블랙박스):

수동 테스트는 프로그래밍 지식 등이 필요하지 않습니다. 테스터는 내부에서 어떤 알고리즘이 실행되는지 모른 채 손으로 앱을 깨뜨리기만 하면 됩니다! 그래서 블랙박스 테스트라고 부릅니다! 새로운 기능을 추가하는 과정에서 다른 부분에서 예상치 못한 동작이 발생할 수 있고, 테스터의 실력이 부족할 수 있기 때문에(결국 우리도 사람이니까요) 신뢰도가 높지는 않습니다.

자동화된 테스트(화이트박스):

반면에 자동화된 테스트는 모든 시나리오에서 앱을 테스트하는 방법을 컴파일러에 알려주고 앱이 제대로 작동하는지 테스트하도록 하기 때문에 프로그래밍 언어가 필요합니다! 그렇기 때문에 수동 테스트보다 더 안정적입니다! 또한 컴파일러가 새로운 기능을 추가하는 동안 기존 기능도 모두 검증하는 누적 방식이기 때문에 매우 안정적입니다. 모든 변경 사항에 대해 앱 전체가 처음부터 끝까지 테스트됩니다! 이를 통해 현재 개발이 기존 기능을 손상시키지 않도록 할 수 있습니다.

이제 자동화된 테스트의 장단점을 살펴보겠습니다!

장점

  • 개발자의 품질을 보여줄 수 있다.
  • 코드 품질을 개선하고 더 나은 코드를 작성하는데 도움이 됩니다. (단일책임, 계층화된 아키텍처, 의존성 주입, 추상화 등 더 나은 코드를 작성하도록 도와줍니다)
  • 복잡하지 않고 명확하고 기본적인 사고를 돕습니다(복잡한 코드를 작성하고 단위 테스트를 작성하는 고통을 느껴보면 확인가능)
  • 많은 시간과 비용을 절약합니다(버그를 식별하는데 도움이 됩니다)
  • 정신력을 유지하고 좌절하지 않도록 도와줍니다(상사와 고객으로부터 불쾌한 피드백을 방지합니다)
  • 예상치 못한 이상한 버그 방지(새로운 기능을 추가하거나 버그를 수정하거나 기존 코드를 리팩토링할때 다른 기능이나 앱 전체가 손상될 수 있습니다.)
  • 뒤처지는것을 방지합니다(전에는 잘 작동했는데! 라는 말을 하지 않아도 됩니다.)
  • 장기적인 유지보수가 더 쉬워집니다.(테스트를 보는것만으로도 테스트의 내용을 쉽게 이해할 수 있습니다.)
  • 자신있게 리팩터링(코드를 리팩토링하는 동안 무언가를 깨뜨릴까 걱정할 필요가 없습니다. 깨지더라도 무엇이 어디에 문제가 있는지 즉시 알 수 있습니다.)
  • 디버깅이 더욱 간편해집니다!(어떤 경우에 실패하고 버그를 일으키는지 정확히 알 수 있습니다.)

단점

  • 시간이 조금 많이 걸릴 수 있습니다.(그러나 개발 시간이 느려 보이더라도 반대로 향후 발생할 많은 버그를 줄이기 때문에 전체적으로는 속도가 빨라집니다)

단위테스트를 하는 경우

  • 초기값이 제대로 설정되었는지
  • 값이 예상대로 업데이트 되었는지
  • 테스트 결과가 예상과 일치하는지 확인
  • 단위가 예상대로 요류를 처리하는지
  • 두번이상 호출해도 단위 테스트가 작동하는지

또한

  • null 케이스 확인
  • 데이터 유형이 참인지 확인

(Dart의 널 및 타입 안전 시스템 덕분에 이러한 변수는 필요하지 않습니다! 동적 및 널 가능 변수를 사용하지 않는 한 말입니다).

플러터에서 테스트하는것

단위 테스트 - 로직 테스트

단일클래스 또는 단일메서드/함수를 테스트하여 정의된 조건에서 논리 단위를 검증하는 경우(메서드를 실행하고 예상대로 작동할것으로 예상)

위젯 테스트 - UI 테스트

단일 UI 위젯과 그 동작을 테스트하려면(버튼을 클릭하고 예상대로 작동할것으로 예상)

골든 테스트 - UI의 적응성 및 반응성 테스트

골든 테스트는 기본적으로 위젯 테스트이지만, 생성된 "골든" 이미지와 위젯이 동일한지 확인하는 테스트입니다.

통합 테스트 - 경험 테스트

사용자 관점에서 앱의 많은 부분을 테스트하는경우(예 : 텍스트 필드를 채우고 로그인 버튼을 클릭한 후 홈페이지 라우팅 예상 등)

E2E 테스트 - 전체 시스템 테스트(프론트앤드+백앤드)

전체 경험을 테스트합니다.

코드를 좀 봅시다

// 어노테이션을 사용하여 전역 규칙을 정의할 수 있습니다!
// 정말 다양한 플랫폼 옵션이 있습니다!
// vm, 크롬, 파이어폭스, 사파리, 노드, 다트-vm, 브라우저, js, 맥-OS, 리눅스, 안드로이드, iOS...js, mac-os, linux, android, ios...
(['browser', 'android'])
('ios')
('currently failing (see issue 1234)')
(Duration(seconds: 45))
({'windows': Timeout.factor(2)})
void main() {
  
  late HttpServer server;
  
  // 테스트가 시작되기 직전에 초기화
  setUp(() async {
    server = await HttpServer.bind('localhost', 0);
  });
  
  // 테스트가 끝나기 전에 닫기
  tearDown(() async {
    await server.close(force: true);
    server = null;
  });
  
  // 테스트 생성
  test('description', () {
    // write your test here
  });
  
  // 테스트 그룹핑
  group(
    'description',
    () {
      test('test1', () {});
      test('test2', () {});
      test('test3', () {});
    },
    skip: 'reason',
  );
  
  // 테스트별 규칙도 정의할 수 있습니다
  test(
    'description', () {},
    // 특정 테스트에 대한 특정 규칙을 정의할 수 있습니다.
    tags: 'chrome', // or ['chrome', 'firefox'],
    skip: 'reason', // skips the test
    timeout: const Timeout.factor(2), // 시간을 2배 느리게하기
    retry: 3, // 테스트를 3번 실행하여 정상인지 확인
    testOn: 'browser && !chrome', // Chrome을 제외한 모든 브라우저
    // 플랫폼별 규칙!
    onPlatform: {
      'windows': const Timeout.factor(2),
      'browser': [const Skip('add browser support')],
    },
  );
  
  // 그리고 네, 어떤 결과든 기대할 수 있습니다!
  // 매처 패키지 덕분에 결과를 일치시킬 수 있는 다양한 방법이 있습니다!
  expect(text.trim(), equals('foo')); // sync
  expect('foo,bar,baz', allOf([contains('foo'), isNot(startsWith('bar')), endsWith('baz')])); // sync
  expect(await Future.value(10), equals(10)); // async
  expectLater(actual, matcher); // async 
  expect(Future.value(10), completion(equals(10))); // async
  expect(Future.error('oh no'), throwsA(equals('oh no'))); // on error
  expect(Future.error(StateError('bad state')), throwsStateError); // on error
  expect(() => int.parse('X'), throwsFormatException); // on error
  expect(stream, emitsInOrder(['ready.', emitsAnyOf(['succeeded', 'failed']), emitsDone])); // stream
}

테스트에 관한 몇가지 무작위 정보

  • 테스트는 빠르고 간단하고 독립적이고 결정론적이며 반복 가능하고 한가지에만 초점을 맞추고 이해하기 쉬어야 합니다.(Arrange-Act-Assert)
  • 테스트에서 코드 반복은 괜찮습니다.(테스트는 좋은 코딩 방법보다는 단순성에 더 중점을 두어야 합니다)
  • 추상 클래스를 사용하면 더 쉬워집니다!.
  • 테스트는 코딩하는 동안 작성해야 합니다! 앱이 완전히 완성되었을때가 아니라!
  • 서비스 테스트는 의심스럽다!(대부분 사용하는 서비스에 대한 테스트를 작성할 필요는 없지만 백엔드 담당자를 믿지 못한다면 앱에서도 서비스 테스트를 작성해야 한다고 생각합니다)
  • 모킹은 의존성을 속이는것일 뿐 입니다. 그 이상 그 이하도 아닙니다.
  • 파일 이름은 "_test.dart" 로 끝나야 합니다.
  • TDD: 먼저 테스트를 작성한 다음 코드를 작성하세요!
  • BDD: 사람이 읽을 수 있는 언어로 테스트 작성(Given-When-Then)
BDD Example

Feature: Counter
Scenario: Increase and decrease the value of the counter
  Given
  Counter's initial value is 0
  And increase and decrease buttons are available
  
  When User click on the increase button.
  Then the counter's value should be 1.
  • 커버리지는 코드가 얼마나 광범위하게 테스트되었는지를 의미합니다.

마지막으로

아무도 테스트를 작성하라고 말하지 않지만 테스트는 사람의 자질을 보여줍니다! - 지혜로운 사람

profile
2021.05.03) Flutter, BlockChain, Sports, StartUp

0개의 댓글