Home > Back-end >  How can I test a method and to mock another method that are in the same class in Flutter
How can I test a method and to mock another method that are in the same class in Flutter

Time:04-08

Description: I have already tested methodA() and methodB() so I can be sure that they are covered. What are the ways to test methodToBeTested() by mocking methodA() and methodB() that are in the same file? The parameters are passed through the methodToBeTested() to the methodA() and methodB() to properly test these methods using injection. Note: They are cannot be extracted to a different class since it is a related logic of the calculation service and these methods are already atomically is separated.

Code:

class ClassForTesting {
  int methodToBeTested(String a, String b) {
     // Calculation in this method also is a bit more difficult
     return methodA()   methodB();
  } 

  int methodA(String a) {
     int value = 1;
     // Here is calculation logic that has been tested
     return value;
  } 

  int methodB(String b) {
     int value = 2;
     // Here is calculation logic that has been tested
     return value;
  } 
}

What has been done: I have tried several approaches from Mockito, but it doesn't allow to do such a trick:

  1. @GenerateMocks - is creating a mock and requires me to stub each method using when(), even methodToBeTested().
  2. By extending Fake using the next construction:
class Mock extends Fake implements PasswordValidatorService {}

But in this way, I'm only inheriting the PasswordValidatorService's behavior instead of instead implementation and each non-overridden method throws UnimplementedError. Thus, I'm not able to override methodToBeTested() and call its super implementation.

I found that Mockito for Java has @Spy construction that would be perfect in this case but unfortunately it is not available for Dart and Flutter.

The only way I currently came is to create my own Mock:

class MockClassForTesting extends ClassForTesting {
  @override
  int methodA() {
    return 2;
  }

  @override
  int methodB() {
    return 5;
  }
}

But this implementation doesn't allow me to use Mockito's flexibility of when() construction since I must have different methodA() and methodB() returns. This fact forces me to have additional variables in my MockClassForTesting to achieve when() construction functionality.

The questions:

  1. What would be the best way to achieve my purposes?
  2. Can be the same mocking approach to be used during the Widget testing?

Thank you!

CodePudding user response:

One approach would be to use a hybrid approach where you create your own derived class but where some of its overrides delegate to a Mock implementation. For example:

class ClassForTesting {
  int methodToBeTested(String a, String b) {
     // Calculation in this method also is a bit more difficult
     return methodA(a)   methodB(b);
  } 

  int methodA(String a) {
     int value = 1;
     // Here is calculation logic that has been tested
     return value;
  } 

  int methodB(String b) {
     int value = 2;
     // Here is calculation logic that has been tested
     return value;
  } 
}

class PartialMockClassForTesting extends ClassForTesting {
  final mock = MockClassForTesting();

  @override
  int methodA(String a) => mock.methodA(a);

  @override
  int methodB(String b) => mock.methodB(b);
}

@GenerateMocks([ClassForTesting])
void main() {
  test('Test partial mock', () {
    var partialMock = PartialMockClassForTesting();
    when(partialMock.methodA('hello')).thenReturn(42);
    when(partialMock.methodA('goodbye')).thenReturn(-42);
    when(partialMock.methodB('world')).thenReturn(10);

    expect(partialMock.methodToBeTested('hello', 'world'), 52);
    expect(partialMock.methodToBeTested('goodbye', 'world'), -32);
  });
}
  • Related