Stub any instance of a class in dart

微笑、不失礼 提交于 2021-01-28 09:01:03

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!