본문 바로가기
다트(Dart) 언어 강좌

단위 테스트 작성하기를 알아보자

by everythingdev 2024. 7. 31.
반응형

단위 테스트 작성하기를 알아보자.

  • 플러터를 시작하기 전 다트(Dart) 언어의 개념에 대해 정리를 해보고자 합니다.
  • 다트(Dart) 언어 개념 정리 포스팅 후 플러터(Flutter) 개념 정리로 넘어갈 예정입니다.
  • 플러터(Flutter) 개념 정리 후 실습이 시작 된다고 보시면 될 것 같습니다.

소개

  • 소프트웨어 개발에서 단위 테스트의 중요성은 아무리 강조해도 지나치지 않다고 볼 수 있습니다.
  • 특히 Dart 언어를 사용하는 개발자들에게 단위 테스트는 코드의 품질을 보장하고 버그를 사전에 방지하는 핵심 도구입니다.
  • 이번 포스팅에서는 Dart에서 효과적인 단위 테스트를 작성하는 방법에 대해 상세히 알아보려고 합니다.

Dart 단위 테스트의 기본

  • Dart에서 단위 테스트를 시작하기 위해서는 먼저 test 패키지를 프로젝트에 추가해야 합니다. 이는 pubspec.yaml 파일에 다음과 같이 의존성을 추가함으로써 가능합니다
dev_dependencies:
  test: ^1.16.0
  • 의존성을 추가한 후, pub get 명령어를 실행하여 패키지를 설치합니다.

테스트 파일 구조

  • Dart에서는 일반적으로 테스트 파일을 test 디렉토리에 위치시킵니다. 테스트 파일의 이름은 보통 {테스트 대상 파일명}_test.dart 형식을 따릅니다.
  • 예를 들어, calculator.dart 파일을 테스트한다면, 테스트 파일의 이름은 calculator_test.dart가 될 것입니다.

첫 번째 테스트 작성하기

  • 간단한 계산기 클래스를 예로 들어 테스트를 작성해 보겠습니다. 먼저 lib/calculator.dart 파일에 다음과 같은 코드를 작성합니다
class Calculator {
  int add(int a, int b) => a + b;
  int subtract(int a, int b) => a - b;
  int multiply(int a, int b) => a * b;
  double divide(int a, int b) {
    if (b == 0) throw ArgumentError('Cannot divide by zero');
    return a / b;
  }
}

  • 이제 이 클래스에 대한 테스트를 test/calculator_test.dart 파일에 작성해 보겠습니다
import 'package:test/test.dart';
import 'package:your_project_name/calculator.dart';

void main() {
  late Calculator calculator;

  setUp(() {
    calculator = Calculator();
  });

  group('Calculator', () {
    test('add two numbers', () {
      expect(calculator.add(2, 3), equals(5));
    });

    test('subtract two numbers', () {
      expect(calculator.subtract(5, 2), equals(3));
    });

    test('multiply two numbers', () {
      expect(calculator.multiply(4, 3), equals(12));
    });

    test('divide two numbers', () {
      expect(calculator.divide(10, 2), equals(5));
    });

    test('throw error when dividing by zero', () {
      expect(() => calculator.divide(10, 0), throwsA(isA<ArgumentError>()));
    });
  });
}

테스트 구조 이해하기

위의 테스트 코드를 자세히 살펴보면 몇 가지 중요한 요소를 발견할 수 있습니다

  1. import 문: 필요한 패키지와 테스트할 클래스를 가져옵니다.
  2. main() 함수: 모든 테스트가 실행되는 진입점입니다.
  3. setUp() 함수: 각 테스트 전에 실행되며, 여기서는 Calculator 인스턴스를 생성합니다.
  4. group() 함수: 관련된 테스트들을 그룹화합니다.
  5. test() 함수: 개별 테스트 케이스를 정의합니다.
  6. expect() 함수: 실제 결과와 예상 결과를 비교합니다.

테스트 실행하기

  • 테스트를 실행하려면 터미널에서 다음 명령어를 사용합니다:
dart test
  • 이 명령어는 test 디렉토리 내의 모든 테스트 파일을 실행합니다.

고급 테스트 기법

비동기 테스트

  • Dart에서 비동기 코드를 테스트할 때는 asyncawait 키워드를 사용합니다.
test('async operation', () async {
  var result = await someAsyncFunction();
  expect(result, equals(expectedValue));
});

매개변수화된 테스트

  • 여러 입력값에 대해 동일한 테스트를 반복하고 싶을 때는 매개변수화된 테스트를 사용할 수 있습니다.
void main() {
  group('Calculator', () {
    final calculator = Calculator();

    [
      [1, 2, 3],
      [10, 20, 30],
      [-1, 1, 0],
    ].forEach((testCase) {
      test('add ${testCase[0]} + ${testCase[1]} = ${testCase[2]}', () {
        expect(calculator.add(testCase[0], testCase[1]), equals(testCase[2]));
      });
    });
  });
}

모의 객체 사용하기

  • 복잡한 의존성을 가진 클래스를 테스트할 때는 모의 객체(Mock)를 사용하면 유용합니다. Dart에서는 mockito 패키지를 사용하여 모의 객체를 생성할 수 있습니다.
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

class MockDatabase extends Mock implements Database {}

void main() {
  late MockDatabase mockDatabase;
  late UserRepository userRepository;

  setUp(() {
    mockDatabase = MockDatabase();
    userRepository = UserRepository(mockDatabase);
  });

  test('fetch user returns user when found', () async {
    when(mockDatabase.getUser(1)).thenAnswer((_) async => User(id: 1, name: 'John'));

    final user = await userRepository.fetchUser(1);

    expect(user.name, equals('John'));
    verify(mockDatabase.getUser(1)).called(1);
  });
}

테스트 커버리지

  • 코드의 어느 부분이 테스트되고 있는지 알아보기 위해 테스트 커버리지를 측정할 수 있습니다. Dart에서는 coverage 패키지를 사용하여 커버리지 보고서를 생성할 수 있습니다.
dart test --coverage=coverage
dart run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.packages --report-on=lib
  • 이 명령어들은 LCOV 형식의 커버리지 보고서를 생성합니다.

결론

  • Dart에서 단위 테스트를 작성하는 것은 코드의 품질을 향상시키고 버그를 줄이는 데 큰 도움이 됩니다. 이 글에서 다룬 기본적인 테스트 작성 방법부터 비동기 테스트, 매개변수화된 테스트, 모의 객체 사용 등의 고급 기법까지 활용하면 더욱 견고한 Dart 애플리케이션을 개발할 수 있습니다.
  • 단위 테스트는 단순히 버그를 찾는 도구가 아닙니다. 이는 코드의 설계를 개선하고, 리팩토링을 용이하게 하며, 개발자에게 코드에 대한 자신감을 줍니다. 따라서 Dart 프로젝트를 시작할 때부터 단위 테스트를 작성하는 습관을 들이는 것이 중요합니다.
  • 마지막으로, 테스트 주도 개발(TDD) 방식을 적용해 보는 것도 좋은 방법입니다. 실제 코드를 작성하기 전에 테스트를 먼저 작성함으로써, 요구사항을 명확히 이해하고 더 나은 설계를 할 수 있습니다. Dart와 함께 단위 테스트를 활용하여 더 나은 소프트웨어를 만들어 나가시기 바랍니다.

맺음말

  • 이번 포스팅에서는 다트의 단위 테스트에 대해 마지막으로 알아보았습니다.
  • 다음 포스팅 부터는 플러터로 찾아 뵙도록 하겠습니다.
반응형