Mockito:在整个控制流中注入模拟
我仍在学习mockito,现在我正在学习如何注入mock。
我有一个正在测试的对象,其特定方法依赖于其他对象。这些对象又依赖于其他对象。我想模拟某些东西,并让这些模拟在执行过程中随处使用——整个方法的控制流。
例如,假设有这样的类:
public class GroceryStore {
public double inventoryValue = 0.0;
private shelf = new Shelf(5);
public void takeInventory() {
for(Item item : shelf) {
inventoryValue += item.price();
}
}
}
public class Shelf extends ArrayList<Item> {
private ProductManager manager = new ProductManager();
public Shelf(int aisleNumber){
super(manager.getShelfContents(aisleNumber);
}
}
public class ProductManager {
private Apple apple;
public void setApple(Apple newApple) {
apple = newApple;
}
public Collection<Item> getShelfContents(int aisleNumber) {
return Arrays.asList(apple, apple, apple, apple, apple);
}
}
我需要编写测试代码,其部分内容如下:
....
@Mock
private Apple apple;
...
when(apple.price()).thenReturn(10.0);
...
...
@InjectMocks
private GroceryStore store = new GroceryStore();
...
@Test
public void testTakeInventory() {
store.takeInventory();
assertEquals(50.0, store.inventoryValue);
}
每当调用 apple.price() 时,我希望使用我的模拟苹果。这可能吗?
编辑:
重要说明...
包含我想要模拟的对象的类确实有该对象的设置器。但是,在我正在测试的级别上,我确实无法处理该类。因此,按照这个示例,虽然 ProductManager 有一个适用于 Apple 的 setter,但我没有办法从 GroceryStore 对象获取 ProductManager。
I'm still learning mockito and right now I'm learning how to inject mocks.
I have an object under test with a particular method that depends on other objects. Those objects, in turn, depend on other objects. I want to mock certain things and have those mocks be used everywhere during execution--throughout the control flow of the method.
For example assume there are classes like:
public class GroceryStore {
public double inventoryValue = 0.0;
private shelf = new Shelf(5);
public void takeInventory() {
for(Item item : shelf) {
inventoryValue += item.price();
}
}
}
public class Shelf extends ArrayList<Item> {
private ProductManager manager = new ProductManager();
public Shelf(int aisleNumber){
super(manager.getShelfContents(aisleNumber);
}
}
public class ProductManager {
private Apple apple;
public void setApple(Apple newApple) {
apple = newApple;
}
public Collection<Item> getShelfContents(int aisleNumber) {
return Arrays.asList(apple, apple, apple, apple, apple);
}
}
I need to write test code with portions along the lines of:
....
@Mock
private Apple apple;
...
when(apple.price()).thenReturn(10.0);
...
...
@InjectMocks
private GroceryStore store = new GroceryStore();
...
@Test
public void testTakeInventory() {
store.takeInventory();
assertEquals(50.0, store.inventoryValue);
}
Whenever apple.price() is called, I want my mock apple to be the one used. Is this possible?
EDIT:
Important note...
the class that contains the object I want to mock does have a setter for that object. However, I don't really have a handle to that class at the level I'm testing. So, following the example, although ProductManager has a setter for Apple, I don't have a way of getting the ProductManager from the GroceryStore object.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是您通过调用 new 而不是注入来创建您所依赖的对象。将
ProductManager
注入Shelf
(例如在构造函数中),并将Shelf
注入GroceryStore
。然后在测试中使用模拟。如果你想使用@InjectMocks,你必须通过setter方法注入。通过构造函数,它可能看起来像这样:
然后你可以测试它模拟所有你依赖的对象:
The problem is you create objects you depend on by calling
new
instead of injecting it. InjectProductManager
intoShelf
(e.g. in constructor), and injectShelf
intoGroceryStore
. Then in test use mocks. If you want to use@InjectMocks
, you have to inject by setter methods.By constructor it could look like this:
Then you can test it mocking all the objects you depend on: