16

我正在研究继承的代码。我编写了一个应该捕获 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#

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

4

5 回答 5

14

Mockito 不能模拟静态方法。您的何时检查无效:

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

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

如果您的班级保持这种状态,则没有更简单的方法可以模拟这种行为。但是,如果您想更改设计并使这两种方法都不是静态的。使用“when”的正确方法是对模拟对象应用检查。例如:

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

但是再一次,这只有在您将类的 getAction 和 getProduct 方法重新设计为非静态时才有效。

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

于 2013-08-20T16:24:54.073 回答
1

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

mockStatic(BasketHelper.class);

然后定义你的存根 -

when(BasketHelper.getAction(request)).thenReturn(0);
when(BasketHelper.getActionProduct(site, request)).thenReturn(product);
于 2013-08-21T12:04:01.123 回答
0

I ran across this thread while trying to fix the same issue in my tests.

In case others see this issue and end up here...In my case it was caused by not using the @PrepareForTest annotation for the support class.

于 2015-01-15T23:54:07.667 回答
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

于 2014-01-08T17:14:51.107 回答
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);


   }
}
于 2020-02-24T05:44:50.073 回答