依赖注入 – 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.

最佳答案 问题是你通过调用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.
点赞