[PLAY STEEM x PWA] 테스트 기반 개발 (Test Driven Development, TDD)

PLAY STEEM 개발자 이타인클럽(@etainclub)입니다.

PLAY STEEM 개발하면서 가장 힘들었던 점은, 테스트 였습니다.

오류가 나서 한가지를 수정하면 다른 쪽에 문제가 생기는 일이 자주 발생했습니다.

바로 테스트 프로그램을 작성하지 않았기 때문에 발생한 문제입니다.

테스트 프로그램을 만들어놨다면, 한 가지를 수정하고 테스트를 돌렸을 때, 다른 쪽에서 문제가 발생하는지 바로 알 수가 있었을 것입니다.

이처럼 테스트는 필수사항이지만, 개발자들이 개발 일정에 쫓겨 테스트 프로그램을 건너뛰는 경우가 많습니다. 특히 저처럼 혼자서 개발하다 보니 테스트 프로그램 작성할 여력이 나지 않았죠!

새롭게 플러터로 개발하는 웹앱 (Progressive Web App, PWA)는 테스트 기반으로 작성해 보려고 합니다.

테스트 코드를 먼저 작성해서 코드를 완성하는 개발 방법을 Test Driven Development (TDD)라고 합니다.

TDD

그 순서는 다음과 같습니다.

  1. 기능에 대한 테스트 코드 작성 -> 당연히 테스트 실패합니다. 기능이 아직 구현되지 않았기 때문에!
  2. 실패한 테스트에 대한 기능을 구현합니다.
  3. 테스트를 다시 실행합니다.
    • 테스트가 성공하면 다음 테스트로 넘어갑니다.
    • 테스트가 실패하면 구현한 코드를 수정합니다.

말은 참 간단합니다. 간단히 말해 아무 것도 없는 상태에서 테스트 할 기능을 테스트하여 실패시키고, 실패하지 않게 기능을 구현하는 방식입니다.

Flutter Unit Test

지난 글에서 스팀잇 포스트 페칭에 성공하여 화면에 출력했습니다. 이 때 포스트를 페칭하기 위해 사용한 함수가 있는데, 이걸 테스트 해보겠습니다.

플러터 테스트 셋업

  • 테스트 패키지 설정
# pubspec.yaml

dev_dependencies:
  flutter_test:
    sdk: flutter
  • 최상위 test 폴더 밑에 dsteem_api_provider_test.dart 파일 생성하고 테스트하고자 하는 코드 import
import 'package:flutter_test/flutter_test.dart';

import 'package:flutter_steem/src/repositories/dsteem_api_provider.dart';

테스트 먼서 실패하고 기능을 구현하는 방식이 아니라, 구현된 코드를 테스트 하는 것입니다.

기능 코드: 포스트 페칭 함수

// src/repositories/dsteem_api_provider.dart

Future<List<Post>> fetchPosts(
      {String? account,
      required String observer,
      required String sort,
      required int limit,
      String? tag,
      PostRef? startPostRef}) async {
    final body =
        '{"jsonrpc":"2.0", "method":"$FETCH_API.$FETCH_METHOD", "params":{"account":"$account","limit":$limit,"sort":"$sort"}, "id":1}';

    var url = Uri.parse(BASE_URL);
    List<Post> postList = [];

    final response = await httpClient.post(url, body: body);
    if (response.statusCode == 200) {
      // convert it to model
      final parsedJson = json.decode(response.body);
      print('parsed result: ${parsedJson['result']}');
      parsedJson['result'].forEach((json) {
        final post = Post.fromJson(json);
        postList.add(post);
      });
      return postList;
    } else {
      throw Exception('error fetching posts');
    }
  }

테스트 함수

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_steem/src/repositories/dsteem_api_provider.dart';

void main() {
  test('FetchItem returns posts models', () async {
    const account = 'etainclub';
    // create dsteem api instance
    final dsteemApi = DSteemApiProvider();

    // replace the http client of dsteem with mockclient
    // dsteemApi.httpClient = MockClient((request) async {
    //   final jsonMap = {'id': postId};
    //   return Response(json.encode(jsonMap), 200);
    // });

    // fetch posts trough mockclient
    final posts = await dsteemApi.fetchPosts(
        account: account, observer: account, sort: 'blog', limit: 10);
    //print('test. posts: $posts');
    expect(posts[0].postRef.author, account);
  });
}

여기서 테스트 하는 것은 fetchPosts 함수를 써서 etainclub의 블로그 데이터를 읽어오고, 그 포스트들의 저자가 etainclub인지 확인하는 것입니다.

위 코드에서 중간에 주석 처리된 부분이 있습니다. 이부분은 실제로 스팀잇 포스트 데이터를 가져오기 않고 가짜 데이터를 가져와서 테스트 하는 것입니다. 이렇게 하면 테스트가 더 빠르겠죠! 그리고 네트워크 연결이 끊겨도 테스트가 가능하구요.
이 방법의 핵심은 fetchPosts에서 네트워크 요청이 발생할 때, 이것을 실제로 요청하지 않고 바꿔치는 것입니다.
dsteemApi.htpClient를 MockClient 인스턴스로 바꿔침으로써, 네트워크 요청을 가로챌 수 있게 됩니다!
참고로, 위 MockClient 코드는 미완성입니다. fetchPosts에서 포스트값을 가지고 후처리 하는 부분이 있는데, 그 부분이 빠져 있어서 에러가 납니다.

결과

플러터는 안드로이드/아이폰 앱, 데스크탑 앱, 웹 브라우저 앱을 모두 하나의 소스로 만들 수 있는 멋진 녀석입니다. 그런데 각 플랫폼에 맞게 테스트를 실행해야 합니다.

웹의 경우는 다음과 같이 테스트를 실행합니다.

$ flutter test --platform chrome
00:11 +1: All tests passed! 

플러터의 테스트 결과는 패스입니다. 테스트 시간이 11초라고 나왔는데, 사실 이것보다 더 걸립니다. 테스트 하나 하기에 너무나도 시간이 많이 걸리는게 플러터의 단점입니다!


테스트를 왜 하나 싶을 수도 있지만, 보다 안정적인 개발 및 편리한 유지를 위해서 꼭 필요합니다. 이번엔 테스트 코드를 꾸준히 만들어 볼 계획입니다.

많은 응원과 관심 부탁드립니다.

Thank You

cc.
@steemcurator01
@steemcurator02
@steemcurator03
@steemcurator04
@steemcurator05
@steemcurator06
@steemcurator07
@steemitblog


https://playsteem.app

Sort:  

ramires gave etainclub gifts(30 SCT).

고생이 많으십니다. 응원을 보내 드립니다 ^^

응원 감사합니다~

진도를 빨리 빼셔서^^ 따라잡기가.... 고생 많으십니다. 항.상.응.원.합.니.닷!