search
LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

Flutter TDD Clean Architecture Course その4 - Data Layer


全体の再把握

CleanArchitecture.jpg

  • Clean Architectureは図の外側が内側に依存する
    • Domain層は独立して、何にも依存しない
  • コーディングも独立した内側から書き始める
    • Entityがない状態だと、Entityを返すUseCaseを作成できない
  • ただし、UseCaseはより外側のRepositoryを使用する
    • これを解決するためにContract(インターフェイス)を用いる
      • UseCaseはRepositoryのインターフェイスの依存するが実装には依存しない
      • UseCaseはRepositoryの実装がない状態で、Repositoryのインターフェイスを継承したRepositoryのmockを使うことでTDDできる

Data Layer

data-layer-diagram.png

Data LayerはModelを扱う

  • DataSourceはRepositoryが返す型は似ているが、以下の点で異なる
    • RepositoryはFailureとしてエラーをインラインで渡したが、DataSourceはExceptionsを投げる
    • RepositoryはNumberTrivia Entityを返したが、DataSourceはNumberTrivia Modelを返す
      • ModelはEntityにJSONを扱うメソッドを追加したものになる

ModelをTDDする

  • ModelがEntityの子クラスであるテスト
number_trivia_model_test.dart
expect(tNumberTriviaModel, isA<NumberTrivia>());

ModelのJSONを扱うメソッドのTDD

  • fixtureを使う
    • testのデータを作るもの

Fixture

trivia.json
{
 "text": "418 is the error code for \"I'm a teapot\" in the Hyper Text Coffee Pot Control Protocol.",
 "number": 418,
 "found": true,
 "type": "trivia"
}
trivia_double.json
{
  "text": "Test Text",
  "number": 1.0,
  "found": true,
  "type": "trivia"
}

fixture_reader

  • testファイルでfixtureを読み込むために、fixture_readerを用いる ```fixture_reader.dart import 'dart:io';

String fixture(String name) => File('test/fixtures/$name').readAsStringSync();
```

fromJson

  • 整数fixtureと少数fixtureを呼ぶ場合のテストを書き、テストが成功するように実装する
    • 整数完成後、少数のテスト失敗→実装修正を書く
number_trivia_model_test.dart
void main() {
  final tNumberTriviaModel = NumberTriviaModel(number: 1, text: 'Test Text');
  ...
  group('fromJson', () {
    test('should return a valid model when the JSON number is an integer', () async {
      // arrange
      final Map<String, dynamic> jsonMap = json.decode(fixture('trivia.json'));
      // act
      final result = NumberTriviaModel.fromJson(jsonMap);
      // assert
      expect(result, tNumberTriviaModel);
    });
    test(
      'should return a valid model when the JSON number is regarded as a double',
      () async {
        // arrange
        final Map<String, dynamic> jsonMap = json.decode(fixture('trivia_double.json'));
        // act
        final result = NumberTriviaModel.fromJson(jsonMap);
        // assert
        expect(result, tNumberTriviaModel);
      },
    );
  });
}}
number_trivia_model.dart
class NumberTriviaModel extends NumberTrivia {
  ...
  factory NumberTriviaModel.fromJson(Map<String, dynamic> json) {
    return NumberTriviaModel(
      text: json['text'],
      number: (json['number'] as num).toInt(),
    );
  }
}

toJson

  • fromJsonと同様
number_trivia_model_test.dart
...
final tNumberTriviaModel = NumberTriviaModel(number: 1, text: 'Test Text');
...
group('toJson', () {
  test(
    'should return a JSON map containing the proper data',
    () async {
      // act
      final result = tNumberTriviaModel.toJson();
      // assert
      final expectedJsonMap = {
        "text": "Test Text",
        "number": 1,
      };
      expect(result, expectedJsonMap);
    },
  );
});
...
number_trivia_model.dart
class NumberTriviaModel extends NumberTrivia {
  ...
  Map<String, dynamic> toJson() {
    return {
      'text': text,
      'number': number,
    };
  }
}

学んだこと

DataSourceとRepositoryの返す型は似ているが大きく異る

  • DataSourceが返す型とRepositoryが返す型は似ているが大きく異なることを本チュートリアルは強調する

    • DataSourceが返す型はModelであり、Repositoryが返す型はEntityである。
      • 最も内側のEntityと、外側にあるModelはコードとふるまいは似ているが、CleanArchitecture上は別物として扱っている
        • コード上異なるのはJSONが扱えるところだけである
        • これは普遍的なビジネスロジックではなく外部のAPIやフレームワークに依存するものである
    • DataSourceとRepositoryが返すエラーも異なる
      • DataSourceは例外を投げる
      • RepositoryはFailureを使うことでインラインでエラーを返さない
  • DataSourceがデータを受け取るまではコントロールできない外部の世界であり、データを受け取ってからはコントロールできる内部の世界であるため、この違いが生じる。DataSourceはその境界に位置する。

fromJson()とtoJson()

fromJson()

  • fromJson()はMapを受け取りModelを生成するため、factoryとなる

toJson()

  • toJson()は引数を受け取らず、自身のプロパティからMapを生成するインスタンスメソッドとなる

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1