使用 MockClient 时获取 null

Getting null when using MockClient

对于我的单元测试,我使用 mockito 4.1.4 这样的:

如果我使用此代码,我正在通过测试:

    test('Adding data manually', () async {
      final GhibliFilms ghibliMock = GhibliFilms();

      ghibliMock.addFilm(FilmModel(
          director: 'test director',
          description: 'test',
          releaseDate: 'test',
          producer: 'test'
      ));

      expect(ghibliMock.films.length, 1);

    });

GhibliFilms addFilm 方法:

  List<FilmModel> _films = [];

  void addFilm(FilmModel film){
    _films.add(film);
  }

一个问题

我想使用MockClient手动控制一些数据,但是当我使用它时我的测试会失败:

这是我的模拟客户端:

class MockClient extends Mock implements GhibliFilms {
  @override
  Future<List<FilmModel>> getFilms() async{
    return null;
  }
}

当我将 final GhibliFilms ghibliMock = GhibliFilms(); 更改为 final MockClient ghibliMock = MockClient();(其余代码保持不变)时,我的测试将失败并显示以下消息:

NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length

我的方法有什么问题?以及如何为我的案例使用 MockClient?

  1. 你创建了 GhibliFilmsMock 但没有存根它的 .films getter,所以默认情况下它会 return nullexpect(ghibliMock.films.length, 1); 因此导致空指针异常。

  2. 如果您的 getFilms 覆盖是为了覆盖 .films getter,则您的覆盖显式 returns null。目前尚不清楚这是为了什么目的。

  3. Adding overridden methods to a Mock is an anti-pattern.

看来你想要这样的东西:

test('Adding data manually', () async {
  final MockClient ghibliMock = MockClient();

  when(ghibliMock.films).thenReturn(FilmModel(
    director: 'test director',
    description: 'test',
    releaseDate: 'test',
    producer: 'test'
  ));

  expect(ghibliMock.films.length, 1);
});

但请注意,该测试完全没有意义,因为它不会测试任何关于您的实际 class.

class MockClient ... implements GhibliFilms 意味着 MockClient 提供了 GhibliFilms 接口,但提供了自己的、完全独立的实现。 Mocks 的目的不是要替换您正在测试的 class;它用于替换您正在测试的代码 所依赖的对象 .

如果您试图替换 GhibliFilms class 中的单个方法,那么您应该只 extend 它并覆盖您想要的特定方法。例如:

class FakeGhibliFilms extends GhibliFilms {
  @override 
  Future<List<FilmModel>> getFilms() async {
    return [
      FilmModel(
        director: 'test director',
        description: 'test',
        releaseDate: 'test',
        producer: 'test',
      )
    ];
  }
}