尝试使用 ApplicationContext 时 PowerMockito 空指针
PowerMockito null pointer when trying to use ApplicationContext
我有一个 class 名称 ServiceLocator
public class ServiceLocator implements ApplicationContextAware {
private transient ApplicationContext _applicationContext;
private static ServiceLocator _instance = new ServiceLocator();
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_instance._applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return _instance._applicationContext;
}
public static Object findService(String serviceName) {
return _instance._applicationContext.getBean(serviceName);
}
}
我正在尝试使用那个 class 将服务查找到审批者 class 方法
public class ApproverService extends AbstractDataService implements IApproverService {
public void updateCompletedInboxStatus(String status) {
IInboxService inboxService = (IInboxService)ServiceLocator.findService("inboxService");
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
使用该代码,我正在尝试使用 PowerMockRunner 编写 Junit
@RunWith(PowerMockRunner.class)
@PrepareForTest({ApproverService.class})
public class ApproverServiceTest {
@InjectMocks
ApproverService approverService;
@Mock
IInboxService inboxService;
@Mock
ServiceLocator serviceLocator;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
RequestAccessHeader reqHdr = new RequestAccessHeader();
reqHdr.setRequestStatus(AccessConstants.REQ_STATUS_HOLD_INT);
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(serviceLocator.findService("inboxService")).thenReturn(inboxService);
approverService.updateCompletedInboxStatus(status);
}
}
但是我得到的是空指针
java.lang.NullPointerException
at com.alnt.fabric.common.ServiceLocator.findService(ServiceLocator.java:25)
at com.alnt.access.approver.service.ApproverServiceTest.updateCompletedInboxStatus(ApproverServiceTest.java:80)
请帮助我找到该问题的解决方案。
静态方法显然没有被模拟。
这个问题很可能是因为你没有在@PrepareForTest
中添加待模拟的class
改为@PrepareForTest({ApproverService.class, ServiceLocator.class})
题外话:
虽然可以编译,但通过实例引用调用静态方法并不是一个好习惯。因此该行应该是 when(ServiceLocator.findService(...)).thenReturn(inboxService)
。
另一个问题是,您尝试使用单例模式但方式不对。单例假设 return 你一个实例,这样调用者就可以调用它的实例方法。您的 findService
最好是一个实例方法,并被称为 ServiceLocator.getInstance().findService(...)
。为了进一步改进,除非你真的需要它是一个单例,否则你应该使它成为一个普通的对象实例并注入到需要它的对象(假设你已经在使用 Spring,我认为没有理由制作一个单例)
静态方法的设置未正确模拟
@RunWith(PowerMockRunner.class)
@PrepareForTest({ServiceLocator.class}) //Prepare static class for mock
public class ApproverServiceTest {
@Mock
IInboxService inboxService;
@Mock
InboxItem item;
@InjectMocks
ApproverService approverService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(ServiceLocator.findService("inboxService")) //<-- NOTE static call
.thenReturn(inboxService);
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
引用Mocking Static Method
被测对象实际上应该被重构以避免服务定位器反模式/代码味道,并且应该通过构造函数注入遵循显式依赖原则。
public class ApproverService extends AbstractDataService implements IApproverService {
private IInboxService inboxService;
@Autowired
public ApproverService(IInboxService inboxService){
this.inboxService = inboxService;
}
public void updateCompletedInboxStatus(String status) {
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
这样,主题 class 就其正确执行其功能所需的内容而言是真实的,
然后可以相应地重构测试
@RunWith(PowerMockRunner.class)
public class ApproverServiceTest {
@Mock
IInboxService inboxService;
@Mock
InboxItem item;
@InjectMocks
ApproverService approverService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
我有一个 class 名称 ServiceLocator
public class ServiceLocator implements ApplicationContextAware {
private transient ApplicationContext _applicationContext;
private static ServiceLocator _instance = new ServiceLocator();
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_instance._applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return _instance._applicationContext;
}
public static Object findService(String serviceName) {
return _instance._applicationContext.getBean(serviceName);
}
}
我正在尝试使用那个 class 将服务查找到审批者 class 方法
public class ApproverService extends AbstractDataService implements IApproverService {
public void updateCompletedInboxStatus(String status) {
IInboxService inboxService = (IInboxService)ServiceLocator.findService("inboxService");
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
使用该代码,我正在尝试使用 PowerMockRunner 编写 Junit
@RunWith(PowerMockRunner.class)
@PrepareForTest({ApproverService.class})
public class ApproverServiceTest {
@InjectMocks
ApproverService approverService;
@Mock
IInboxService inboxService;
@Mock
ServiceLocator serviceLocator;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
RequestAccessHeader reqHdr = new RequestAccessHeader();
reqHdr.setRequestStatus(AccessConstants.REQ_STATUS_HOLD_INT);
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(serviceLocator.findService("inboxService")).thenReturn(inboxService);
approverService.updateCompletedInboxStatus(status);
}
}
但是我得到的是空指针
java.lang.NullPointerException at com.alnt.fabric.common.ServiceLocator.findService(ServiceLocator.java:25) at com.alnt.access.approver.service.ApproverServiceTest.updateCompletedInboxStatus(ApproverServiceTest.java:80)
请帮助我找到该问题的解决方案。
静态方法显然没有被模拟。
这个问题很可能是因为你没有在@PrepareForTest
改为@PrepareForTest({ApproverService.class, ServiceLocator.class})
题外话:
虽然可以编译,但通过实例引用调用静态方法并不是一个好习惯。因此该行应该是 when(ServiceLocator.findService(...)).thenReturn(inboxService)
。
另一个问题是,您尝试使用单例模式但方式不对。单例假设 return 你一个实例,这样调用者就可以调用它的实例方法。您的 findService
最好是一个实例方法,并被称为 ServiceLocator.getInstance().findService(...)
。为了进一步改进,除非你真的需要它是一个单例,否则你应该使它成为一个普通的对象实例并注入到需要它的对象(假设你已经在使用 Spring,我认为没有理由制作一个单例)
静态方法的设置未正确模拟
@RunWith(PowerMockRunner.class)
@PrepareForTest({ServiceLocator.class}) //Prepare static class for mock
public class ApproverServiceTest {
@Mock
IInboxService inboxService;
@Mock
InboxItem item;
@InjectMocks
ApproverService approverService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(ServiceLocator.findService("inboxService")) //<-- NOTE static call
.thenReturn(inboxService);
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
引用Mocking Static Method
被测对象实际上应该被重构以避免服务定位器反模式/代码味道,并且应该通过构造函数注入遵循显式依赖原则。
public class ApproverService extends AbstractDataService implements IApproverService {
private IInboxService inboxService;
@Autowired
public ApproverService(IInboxService inboxService){
this.inboxService = inboxService;
}
public void updateCompletedInboxStatus(String status) {
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
这样,主题 class 就其正确执行其功能所需的内容而言是真实的,
然后可以相应地重构测试
@RunWith(PowerMockRunner.class)
public class ApproverServiceTest {
@Mock
IInboxService inboxService;
@Mock
InboxItem item;
@InjectMocks
ApproverService approverService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}