简体   繁体   English

如何在 repo 中测试/模拟 Hive (Flutter) 打开盒子逻辑?

[英]How can I test / mock Hive (Flutter) open box logic in repo?

Sorry if this seems a dumb question.对不起,如果这看起来是一个愚蠢的问题。 I'm learning clean architecture as dictated by Rob Martin, and I've having a tiny bit of trouble writing one of my tests.我正在按照 Rob Martin 的指示学习干净的体系结构,并且在编写我的一个测试时遇到了一点点麻烦。

I wrote a couple functions in a Hive repo.我在 Hive 存储库中编写了几个函数。 Here's the code这是代码

import 'package:hive/hive.dart';
import 'package:movie_browser/features/SearchMovie/domain/entities/movie_detailed_entity.dart';

abstract class HiveMovieSearchRepoAbstract {
  Future<void> cacheMovieDetails(MovieDetailed movie);
  Future<MovieDetailed> getCachedMovieDetails(String id);
}

// const vars to prevent misspellings
const String MOVIEDETAILSBOX = "MovieDetailedBox";
const String SEARCHBOX = "SearchBox";

class HiveMovieSearchRepo implements HiveMovieSearchRepoAbstract {
  Box movieDetailsBox = Hive.box(MOVIEDETAILSBOX) ?? null;
  // TODO implement searchbox
  // final searchBox = Hive.box(SEARCHBOX);

  Future<void> cacheMovieDetails(MovieDetailed movie) async {
    /// expects a MovieDetailed to cache.  Will cache that movie
    movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);

    movieDetailsBox.put('${movie.id}', movie);
  }

  Future<MovieDetailed> getCachedMovieDetails(String id) async {
    /// expects a string id as input
    /// returns the MovieDetailed if cached previously
    /// returns null otherwise
    movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);

    return await movieDetailsBox.get('$id');
  }

  _openBox(Box box, String type) async {
    await Hive.openBox(type);
    return Hive.box(type);
  }
}

I can't think of how to test this?我想不出如何测试这个? I want two cases, one where the box is already opened, and one case where it isn't.我想要两种情况,一种箱子已经打开,一种箱子没有。

Specifically, it's these lines I want to test具体来说,我要测试的是这些行

movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);

_openBox(Box box, String type) async {
    await Hive.openBox(type);
    return Hive.box(type);
  }

I thought about mocking the Box object then doing something like....我想到了 mocking Box object 然后做类似的事情......

when(mockHiveMovieSearchRepo.getCachedMovieDetails(some_id)).thenAnswer((_) async => object)

but wouldn't that bypass the code I want tested and always show as positive?但这不会绕过我要测试的代码并始终显示为阳性吗?

Thanks so much for the help非常感谢你的帮助

i don't know if i fully understand your question but you can try something like this我不知道我是否完全理解你的问题,但你可以尝试这样的事情

abstract class HiveMovieSearchRepoAbstract {
  Future<void> cacheMovieDetails(MovieDetailed movie);
  Future<MovieDetailed> getCachedMovieDetails(String id);
}

// const vars to prevent misspellings
const String MOVIEDETAILSBOX = "MovieDetailedBox";
const String SEARCHBOX = "SearchBox";

class HiveMovieSearchRepo implements HiveMovieSearchRepoAbstract {
  final HiveInterface hive;

  HiveMovieSearchRepo({@required this.hive});

  @override
  Future<void> cacheMovieDetails(MovieDetailed cacheMovieDetails) async {
    /// expects a MovieDetailed to cache.  Will cache that movie
    try {
      final moviedetailbox = await _openBox(MOVIEDETAILSBOX);
      moviedetailbox.put('${movie.id}', movie);
    } catch (e) {
      throw CacheException();
    }
  }

  Future<MovieDetailed> getCachedMovieDetails(String id) async {
    /// expects a string id as input
    /// returns the MovieDetailed if cached previously
    /// returns null otherwise
    try {
      final moviedetailbox = await _openBox(MOVIEDETAILSBOX);
      if (moviedetailbox.containsKey(boxkeyname)) {
        return await movieDetailsBox.get('$id');
      }
      return null;
    } catch (e) {
      return CacheException();
    }
  }

  Future<Box> _openBox(String type) async {
    try {
      final box = await hive.openBox(type);
      return box;
    } catch (e) {
      throw CacheException();
    }
  }
}

And to test it you can do something like this为了测试它,你可以做这样的事情

class MockHiveInterface extends Mock implements HiveInterface {}

class MockHiveBox extends Mock implements Box {}

void main() {
  MockHiveInterface mockHiveInterface;
  MockHiveBox mockHiveBox;
  HiveMovieSearchRepo hiveMovieSearchRepo;
  setUp(() {
    mockHiveInterface = MockHiveInterface();
    mockHiveBox = MockHiveBox();
    hiveMovieSearchRepo = HiveMovieSearchRepo(hive: mockHiveInterface);
  });

  group('cacheMoviedetails', () {

    
    test(
    'should cache the movie details',
     () async{
        //arrange
         when(mockHiveInterface.openBox(any)).thenAnswer((_) async => mockHiveBox);
        //act
      await hiveMovieSearchRepo.cacheMovieDetails(tcacheMovieDetails);
        //assert
      verify(mockHiveBox.put('${movie.id}', tmovie));
      verify(mockHiveInterface.openBox("MovieDetailedBox"));
      });
    
  });

  group('getLocalCitiesAndCountriesAtPage', () {
    test('should when', () async {
      //arrange
      when(mockHiveInterface.openBox(any))
          .thenAnswer((realInvocation) async => mockHiveBox);
      when(mockHiveBox.get('$id'))
          .thenAnswer((realInvocation) async => tmoviedetails);
      //act
      final result =
          await hiveMovieSearchRepo.getCachedMovieDetails(tId);
      //assert
      verify(mockHiveInterface.openBox(any));
      verify(mockHiveBox.get('page${tpage.toString()}'));
      expect(result, tmoviedetails);
    });
  });

}

You should add some tests also for the CacheExeption().您还应该为 CacheExeption() 添加一些测试。 Hope this help you.希望这对你有帮助。

So, I wrote this post 9 months.所以,我写了这篇文章 9 个月。 Stackoverflow just sent me a notification saying it's a popular question, so I'll answer it for anyone else wondering the same thing Stackoverflow 刚刚给我发了一条通知,说这是一个热门问题,所以我会为其他想知道同样问题的人回答

Easy way to make this testable is change Box to an arg passed into the class, like so使此可测试的简单方法是将 Box 更改为传递到 class 的 arg,如下所示

abstract class ClassName {
  final Box movieDetailsBox;
  final Box searchBox;

  ClassName({
    this.moveDetailsBox,
    this.searchBox,
  });
}

this makes the boxes mockable and testable这使得盒子可模拟和可测试

You should mock the hive interface and box;你应该mock hive接口和盒子;

I have faced an issue, and this is when I opened the box and initialized mockHiveBox.我遇到了一个问题,这是我打开盒子并初始化 mockHiveBox 的时候。 When I want to get box.values I receive an error which is Exception: type 'Null' is not a subtype of type 'Iterable' .当我想获取 box.values 时,我收到一个错误Exception: type 'Null' is not a subtype of type 'Iterable'

print box.values method打印 box.values 方法

get customer box获取客户框

open box method with mock带模拟的开箱方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM