问题
Developing with ruby on rails allowed to do things like :
File.any_instance.expects(:delete)
This was a great way to test for side effects within a method call.
How to do the equivalent in dart?
For example if you have in dart :
class Storage {
// the function to test
void deleteFile(String path) {
var fileToDelete = new File(path);
if (await fileToDelete.exists()) {
await fileToDelete.delete();
}
}
}
...
test("#deleteFile delete the file exists", () {
storage = new Storage();
// something equivalent to "File.any_instance.expects(:delete).once"
storage.deleteFile("/existing.txt")
});
test("#deleteFile does not try to delete the file when it does not exists", () {
storage = new Storage();
// something equivalent to "File.any_instance.expects(:delete).never"
storage.deleteFile("/not_existing.txt")
});
How would you write detect that an instance of File
has been called with the correct parameters?
There is some patterns that exist that would make this testable as explained in here : https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
However, these two patterns require to modify the class in order to make it more testable, by either isolating the File
object creation in his own method then stubbing this method or using a factory to infer the mock when instantiating the Storage
class.
I would like to find a way to do this without having to modify the class to make it more testable like in ruby.
This could be also very useful to check if some logs were produced during the method execution.
回答1:
There is no general way to intercept static method calls (including constructors) or instance members on existing objects in Dart.
The only way you can know when some method is called is if you can wrap the object that the method is called on, before the object reference is passed to the caller. Because Dart allows any class interface to be implemented, you can wrap any object that you know of, as long as you can get between the creator of the object and the user (and if you are the creator, you can create a mock instead of ever having a real object). That approach still cannot work for static methods.
That is, you need some abstraction layer where you can substitute code instead of the default behavior.
The way your current issue is phrased, it cannot be solved. You cannot change the object created by the File
constructor, and you cannot change what happens when its delete
method is called. There are no hooks to allow that.
You need to rewrite the Storage
class in some way to introduce the abstraction that allows you to get between the class and the File
object, maybe taking a File createFile(String path)
function that it uses instead of new File
.
回答2:
You can build mocks using https://pub.dartlang.org/packages/mockito or implement yout own mock like
class StorageMock extends Mock implements Storage {
void delete(String path) {
..
}
}
来源:https://stackoverflow.com/questions/49960202/stub-any-instance-of-a-class-in-dart