-
Notifications
You must be signed in to change notification settings - Fork 164
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
Mock functions? #62
Comments
A concrete example what you're trying to accomplish? |
I'm not really proficient with mocks, but you should be able to mock the |
Example: typedef A SomethingIWantToMock(B b, C c);
void somethingIWantToTest(D d, E e, SomethingIWantToMock mock) {
[the code to test...]
A a = mock(something, something);
[more code to test...]
}
test('check that somethingIWantToTest interacts correctly with SomethingIWantToMock', () {
SomethingIWantToMock mock = [make a mock...];
when(mock).thenAnswer((Invocation invocation) => [use b, use c]);
somethingIWantToTest(mock);
assert
assert
verify(mock)
verify(mock)
}); More or less the same as class mocking but with functions. |
cc @cbracken FYI |
I think the main issue here is that it won't be possible to create a single "Mock" function that could represent (statically) any function. In this particular case, it might honestly be simpler to just create a stub implementation of your function: test('...', () {
void stubDoSomething(a, b, c) {
// ...
}
}; |
Hi @xster yeah this is, with the current implementation, impossible I think @matanlurey 's suggestion should work perfectly if you get to inject the function into |
If you want to just create a mocked function to use as onTap on widget test environment, with mockito you can do something like that:
Test:
|
It's now very easy to mock functions. You just need to mock an abstract class that contains all the functions you need as methods, and then pass the methods as the needed functions. Here's a full example: import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'example_test.mocks.dart';
/// The function to test
Future<DateTime> getCurrentTime(
Future<String> Function(String) postRequest) async {
String r = await postRequest('getCurrentTime');
return DateTime.fromMillisecondsSinceEpoch(int.parse(r) * 1000, isUtc: true);
}
abstract class MyFuncs {
Future<String> postRequest(String name);
}
@GenerateMocks([MyFuncs])
void main() {
test('getCurrentTime', () async {
final myFuncs = MockMyFuncs();
when(myFuncs.postRequest('getCurrentTime'))
.thenAnswer((_) async => '1647249645');
final dt = await getCurrentTime(myFuncs.postRequest);
expect(dt, DateTime.utc(2022, 3, 14, 9, 20, 45));
});
}
|
@srawlins - I just saw the pattern of mocking an abstract class for it's tearoffs used in a code review and it surprised me at first. Do you think it would be reasonable to more directly support mocking callbacks now that we have codegen? We could feasibly turn A few points to consider:
Future<String> Function(String) mockPostRequest() => _MockPostRequest().call; |
This is a very cool idea. Something like |
About this point, I have a slightly different problem that I don't know how to solve myself: // application/repository/todo.dart
import 'package:flutter/foundation.dart';
import 'package:port_domain/networking.dart';
import 'package:todo/domain/todo.dart';
class TodoRepository {
final RestClient _client;
final String _baseUrl;
List<Todo> todos = [];
TodoRepository(this._client, this._baseUrl);
Future<void> fetchFromRemote() async {
Response groupRes = await _client.get(
_baseUrl + 'api/todos',
parser: (data) => compute(Todo.fromJsonList, data as List),
);
if (groupRes is Success) {
todos.clear();
todos.addAll(groupRes.result);
}
}
} import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:port_domain/networking.dart';
import 'package:todo/application/repository/todo.dart';
@GenerateMocks([RestClient])
import 'repository_todo_test.mocks.dart';
void main() {
late RestClient client;
late TodoRepository repository;
setUp(() {
client = MockRestClient();
repository = TodoRepository(client, '');
});
group('TodoRepository', () {
test('should have entities available after a successful fetch', () async {
var todoList = [const Todo(id: 1)];
when(
client.get(
'api/todos',
parser: any, // <-- This fails because any isn't supported
),
).thenAnswer((_) async => Success<List<Todo>>(todoList));
await repository.fetchFromRemote();
expect(repository.todos, equals(todoList));
});
});
} Can someone point me out to a way to test it? The problem here is that the Repository creates a closure that should be identified by mockito as the same function. |
@neokree You have to use |
Regarding adding support for mocking functions: definitely doable with codegen, but not sure it's a high priority for us. Will be happy to review changes. |
Towards #62 Update the README and example usage with an example of writing a class to hold the callback signatures and mocking it with codegen. Demonstrate that the callbacks can be stubbed after being torn off. PiperOrigin-RevId: 546011492
Towards #62 Update the README and example usage with an example of writing a class to hold the callback signatures and mocking it with codegen. Demonstrate that the callbacks can be stubbed after being torn off. PiperOrigin-RevId: 546817751
Towards dart-lang/mockito#62 Update the README and example usage with an example of writing a class to hold the callback signatures and mocking it with codegen. Demonstrate that the callbacks can be stubbed after being torn off. PiperOrigin-RevId: 546817751
Don't really know how or if this is achievable but it would be great if there's some magical means to create a mock function rather than a mock class that can be passed into things expecting any sort of typedefs or function signatures and then verify its (dynamic) calls and args.
The text was updated successfully, but these errors were encountered: