Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with mocking riverpod providers #255

Open
Vera-Spoettl opened this issue Jan 9, 2025 · 1 comment
Open

Problems with mocking riverpod providers #255

Vera-Spoettl opened this issue Jan 9, 2025 · 1 comment

Comments

@Vera-Spoettl
Copy link

Vera-Spoettl commented Jan 9, 2025

Describe the bug
I want to write an unit test for a method that is part of a notifier (Provider A). I'll try to explain with a very simple example:

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:test_notifier/provider_b.dart';

part 'provider_a.g.dart';

@riverpod
class ProviderA extends _$ProviderA {
  @override
  int build() {
    return 0;
  }

  void increment() {
    ref.read(providerBProvider.notifier).increment();
  }
}

As you can see, increment calls another notifier's method (ProviderB -> increment).

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'provider_b.g.dart';

@riverpod
class ProviderB extends _$ProviderB {
  @override
  int build() {
    return 0;
  }

  void increment() {
    state++;
  }
}

I would like to write a test now that verifies if Provider B's method increment was call once.

import 'package:flutter/material.dart';
import 'package:test/test.dart';
import 'package:riverpod/riverpod.dart';
import 'package:test_notifier/provider_a.dart';
import 'package:test_notifier/provider_b.dart';
import 'package:mocktail/mocktail.dart';

class MockProviderB extends AutoDisposeNotifier<int>
    with Mock
    implements ProviderB {
  @override
  int build() {
    return 0;
  }

  @override
  void increment() {
    debugPrint('increment providerB in Mock implementation');
  }
}

void main() {
  late ProviderContainer container;
  MockProviderB mockProviderB = MockProviderB();

  setUp(() {
    container = ProviderContainer(
      overrides: [
        providerBProvider.overrideWith(() => mockProviderB),
      ],
    );
  });

  tearDown(() {
    container.dispose();
  });

  test('ProviderB is called once', () {
    final providerA = container.read(providerAProvider.notifier);
    providerA.increment();
    verify(() => mockProviderB.increment).called(1);
  });
}

To Reproduce

Reproducdable by the code above.

Expected behavior
I would have expected that verify(() => mockProviderB.increment()).called(1); should work fine.

What I get instead is the following:

image

It looks as if mockProviderB was never called ...

image

However, when I look at the debug window, I get the following:
image

So, the mock's implementation was called. It seems as if the override works for the invocation but not for the verify statement.

Can you help me whats wrong in my code? Remi from riverpod told me that I'm using mocktail wrong. So how should I implement a test that checks whether notifier A calls notifier B when only the internal state of the notifier is change and not the public model?

@moderateroni
Copy link

two things:

  • you have to call the function by using brackets after mockProvider.increment
  • you should not implement increment in your mock, because Mock will only do its magic if the implementation is missing

in total this works then:

class MockProviderB extends AutoDisposeNotifier<int> with Mock implements ProviderB {}

void main() {
  late ProviderContainer container;
  MockProviderB mockProviderB = MockProviderB();

  setUp(() {
    container = ProviderContainer(
      overrides: [
        providerBProvider.overrideWith(() => mockProviderB),
      ],
    );
  });

  tearDown(() {
    container.dispose();
  });

  test('ProviderB is called once', () {
    final providerA = container.read(providerAProvider.notifier);
    providerA.increment();
    verify(() => mockProviderB.increment()).called(1);
  });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants