Mockito:在整个控制流程中注入模拟

时间:2010-10-15 12:21:10

标签: dependency-injection junit mocking mockito

我还在学习模拟,现在我正在学习如何注射嘲笑。

我有一个正在测试的对象,它使用一种依赖于其他对象的特定方法。反过来,这些对象依赖于其他对象。我想嘲笑某些事情并在执行过程中随处使用这些模拟 - 在整个方法的控制流程中。

例如,假设有类似的类:

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()时,我都希望我的模拟苹果成为使用过的苹果。这可能吗?

编辑:
重要提示......
包含我想要模拟的对象的类确实有一个该对象的setter。但是,在我正在测试的级别上,我并没有真正掌握该类。因此,按照这个例子,虽然ProductManager有一个Apple的setter,但是我没办法从GroceryStore对象中获取ProductManager。

1 个答案:

答案 0 :(得分:2)

问题是您通过调用new而不是注入它来创建您所依赖的对象。将ProductManager注入Shelf(例如在构造函数中),并将Shelf注入GroceryStore。然后在测试中使用模拟。如果你想使用@InjectMocks,你必须通过setter方法注入。

通过构造函数,它看起来像这样:

public class GroceryStore {
  public double inventoryValue = 0.0;
  private shelf;

  public GroceryStore(Shelf shelf) {
    this.shelf = shelf;
  }

  public void takeInventory() {
    for(Item item : shelf) {
      inventoryValue += item.price();
    }
  }
}

public class Shelf extends ArrayList<Item> {
  private ProductManager manager;

  public Shelf(int aisleNumber, ProductManager manager) {
    super(manager.getShelfContents(aisleNumber);
    this.manager = manager;
  }
}

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 ProductManager manager = new ProductManager();

private Shelf shelf = new Shelf(5, manager);
private GroceryStore store = new GroceryStore(shelf);

//Then you can test your store.