Mockito when()。thenReturn不必要地调用该方法

时间:2013-08-20 16:11:56

标签: java testing junit mockito

我正在研究一个继承的代码。 我写了一个应该捕获NullPointerException的测试(因为它试图从null对象调用一个方法)

@Test(expected=NullPointerException.class)
public void checkXRequirement_NullProduct_AddAction_ShouldThrowNullPointerException() throws CustomException {
  Site site = mock(Site.class);
  Product product = null;
  when(BasketHelper.getAction(request)).thenReturn(0);
  when(BasketHelper.getActionProduct(site, request)).thenReturn(product);
  BasketHelper.requiresX(request, site);

}

相关方法和变量:

public static final int ACTION_ADD = 0;
public static final int ACTION_DELETE = 1;

protected static int getAction(HttpServletRequest a_request) {
  String sBuyProduct = a_request.getParameter(ATTRIBUTE_NAME_BUY_PRODUCT);
  String sBuyProduct = a_request.getParameter(ATTRIBUTE_NAME_BUY_PRODUCT);

  if (sBuyProduct != null) iAction = ACTION_ADD;
  else (sDelProduct != null) iAction = ACTION_DELETE;

  return iBasketAction
}

protected static Product getActionProduct(Site a_site, HttpServletRequest a_request) {

    String sBuyProduct = a_request.getParameter(ATTRIBUTE_NAME_BUY_PRODUCT);
    String sDelProduct = a_request.getParameter(ATTRIBUTE_NAME_DEL_PRODUCT);
    String sProduct = null;

    switch (getBasketAction(a_request)) {
        case BASKET_ACTION_ADD:
        sProduct = sBuyProduct;
    break;
        case BASKET_ACTION_DELETE:
        sProduct = sDelProduct;
    break;
    }

    int iProductId;
    try {
        iProductId = Integer.parseInt(sProduct);
    } catch (NumberFormatException nbrEx) {
        return null;
    }

    Product prod = getProductById(iProductId);

    if (prod.isMasterProduct()) {
        prod = getChildProduct(prod, a_site, a_request);
    }

    return prod;
}


public static boolean requiresX(HttpServletRequest request, Site site) throws CustomException {
  try{
    if (getAction(request) == ACTION_ADD) { 
    Product prod = getActionProduct(site, request);
    return prod.getType().isRequiredX();
    }  
  } catch(NullPointerException exception) {
    log.error("Error Message", exception);
  }
  return false;
}

运行测试的jUnit结果是失败,堆栈跟踪为:

java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<org.mockito.exceptions.misusing.WrongTypeOfReturnValue>
Caused by: org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Integer cannot be returned by getParameter()
getParameter() should return String#

我是否误解了何时()。thenReturn应该在这里工作?我只是希望getAction返回0并且getActionProduct在被调用时返回null。很明显,getParameter()被调用,我不知道为什么。

5 个答案:

答案 0 :(得分:14)

Mockito无法模拟静态方法。您的检查无效:

  when(BasketHelper.getAction(request)).thenReturn(0);
  when(BasketHelper.getActionProduct(site, request)).thenReturn(product);

这是我们想要减少静态方法使用的另一个原因,因为它很难模拟。

如果您的班级保持这样,没有更简单的方法来模仿行为。但是,如果您想要更改设计并使两种方法都是非静态的。使用“when”的正确方法是对mocked对象应用检查。例如:

  BasketHelper basketHelper = mock(BasketHelper.class);
  when(basketHelper.getAction(request)).thenReturn(0);
  when(basketHelper.getActionProduct(site, request)).thenReturn(product);

但是,如果您将类的getAction和getProduct方法重新设计为非静态的,那么这只会起作用。

我记得有一些其他测试框架支持模拟静态方法。

答案 1 :(得分:1)

您可以使用PowerMock。首先创建要调用静态方法的类的模拟 -

mockStatic(BasketHelper.class);

然后定义你的存根 -

when(BasketHelper.getAction(request)).thenReturn(0);
when(BasketHelper.getActionProduct(site, request)).thenReturn(product);

答案 2 :(得分:0)

这可以帮助其他使用注释的人。如果您正在使用注释,则可能需要使用@Mock而不是@InjectMocks。因为@InjectMocks在@Spy和@Mock一起工作。并且@Spy会跟踪最近执行的方法,您可能会觉得返回/提交了不正确的数据。 检查这两个:

https://groups.google.com/forum/?fromgroups#!topic/mockito/9WUvkhZUy90

http://code.google.com/p/mockito/issues/detail?id=127

答案 3 :(得分:0)

我试图在我的测试中修复同样的问题时遇到了这个问题。

如果其他人看到这个问题并最终在这里......在我的情况下,这是因为没有对支持类使用@PrepareForTest注释。

答案 4 :(得分:0)

尽管模拟静态方法,私有方法或构造函数不是一种好的编码实践。但是,如果有一些遗留代码,则需要对其进行模拟。那么在那种情况下,可以将Powermock与Mockito结合使用。

使用powermock模拟静态方法时应遵循的步骤。
1)使用特定的Runner,即 PowerMockRunner.class
2)使用注释 @PrepareForTest(UtilityClass.class)
3)初始化包含静态方法的实用程序类。
4)模拟所需的静态方法。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Utility.class)
public class mockingStaticMethod(){

@Mock
Dependency dependency;

@InjectMocks
SystemUnderTest systemUnderTest;

@Test
public void testStaticMethod(){

    PowerMockito.mockStatic(Utility.class);
    When(Utility.staticMethod(arguments)).thenReturn(expectedValue);
    //systemUnderTest class uses the static method present in Utility class 
    //within the methodCallingStaticMethod()
    result = systemUnderTest.methodCallingStaticMethod();
    assertEquals(expectedValue, actualValue);


   }
}