guricode

[클린아키텍쳐]Clean Architecture -3 본문

앱/Flutter&Dart

[클린아키텍쳐]Clean Architecture -3

agentrakugaki 2025. 8. 30. 19:33

 

Domain에 entity를 생성한다

//movie.dart

//현재는 Dto와 똑같아서 별 쓸모없어보이지만 나중에 dto와 상이한 경우가 많다
class Movie {
  final String title;
  final String released;
  final String runtime;
  final String director;
  final String actors;
  final String poster;

  //생성자 호출해서 값 초기화,기본생성자
  Movie({
    required this.title,
    required this.released,
    required this.runtime,
    required this.director,
    required this.actors,
    required this.poster,
  });
}

 

Domain에 repository를 생성한다

 

//movie_repository.dart

//레포지토리 구현하기위해 인터페이스작성
import 'package:flutter_clean_arch/domain/entity/movie.dart';

abstract interface class MovieRepository {
  //fetchMovies정의
  Future<List<Movie>> fetchMovies();
}

//data/movie_repository_impl에서 구현

 

repository에 있는 인터페이스를 사용하여 repository 구현한다.

 

//movie_repository_impl.dart

import 'package:flutter_clean_arch/data/data_source/movie_data_source.dart';
import 'package:flutter_clean_arch/domain/entity/movie.dart';
import 'package:flutter_clean_arch/domain/repository/movie_repository.dart';

//데이터 소스를 데이터소스 인터페이스로 접근
class MovieRepositoryImpl implements MovieRepository {
  //<List<MovieDto>>타입의 _movieDataSource변수 선언
  final MovieDataSource _movieDataSource;
  //생성자로 초기화
  MovieRepositoryImpl(this._movieDataSource);
  //
  @override
  Future<List<Movie>> fetchMovies() async {
    //result는List<MovieDto>타입이라 케스팅 필요함
    final result = await _movieDataSource.fetchMovies();
    return result
        .map(
          //MovieDto타입을 Movie 리스트로 변환하기위해
          //result map으로 요소 순회하여 movie객체로 리턴해준다
          (e) => Movie(
            title: e.title,
            released: e.released,
            runtime: e.runtime,
            director: e.director,
            actors: e.actors,
            poster: e.poster,
          ),
        ) //순환하여 요소들을 Movie객체로 만들었고 그 객체들을 List로 케스팅
        .toList();
  }
}

 

 

이제 테스트 코드를 작성하여 테스트한다

 

//movie_repository_impl_test.dart

import 'package:flutter_clean_arch/data/data_source/movie_data_source.dart';
import 'package:flutter_clean_arch/data/dto/movie_dto.dart';
import 'package:flutter_clean_arch/data/repository/movie_repository_impl.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockMovieDataSource extends Mock implements MovieDataSource {}

void main() {
  //MovieDataSource를 내포한 MockMovieDataSource 타입의 mockMovieDataSource 선언
  MockMovieDataSource? mockMovieDataSource;
  MovieRepositoryImpl? movieRepositoryImpl;
  setUp(() {
    mockMovieDataSource = MockMovieDataSource();
    movieRepositoryImpl = MovieRepositoryImpl(mockMovieDataSource!);
  });

  test('MovieRepositoryImpl test : fetchMovies', () async {
    //mock클래스셋팅
    when(() => mockMovieDataSource!.fetchMovies()).thenAnswer(
      (_) async => [
        MovieDto(
          title: 'title',
          released: 'released',
          runtime: 'runtime',
          director: 'director',
          actors: 'actors',
          poster: 'poster',
        ),
      ],
    );

    final result = await movieRepositoryImpl!.fetchMovies();

    expect(result.length, 1);
    expect(result.first.title, 'title');
  });
}

 

여기서 주의할점은 mockMovieDataSource는 MovieDto 타입이다.

movieRepositoryImpl.FetchMovies가 타입을 List Movie객체로 되돌려주기때문에 마지막 타입은 List<Movie>가 된다