尝试使用ApplicationContext时PowerMockito空指针

时间:2019-11-19 03:32:46

标签: java junit4 powermock

我有一个类名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);
    }
}

我正在尝试使用该类将Service查找到批准者类方法中

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       在com.alnt.fabric.common.ServiceLocator.findService(ServiceLocator.java:25)       在com.alnt.access.approver.service.ApproverServiceTest.updateCompletedInboxStatus(ApproverServiceTest.java:80)

请帮助我找到该问题的解决方案。

2 个答案:

答案 0 :(得分:1)

显然没有模拟静态方法。

问题很可能是因为您没有在@PrepareForTest中添加要模拟的类

将其更改为@PrepareForTest({ApproverService.class, ServiceLocator.class})


题外话

尽管可以编译,但通过实例引用调用静态方法不是一个好习惯。因此,该行应为when(ServiceLocator.findService(...)).thenReturn(inboxService)

另一个问题是,您尝试使用Singleton模式,但方式错误。假设单例返回一个实例,以便调用者可以调用其实例方法。您的findService优选是实例方法,被称为ServiceLocator.getInstance().findService(...)。为了进一步改进,除非您真的需要将其作为单例,否则应将其设为普通的对象实例,并注入需要该对象的对象(假设您已经在使用Spring,我认为没有必要制作单例)

答案 1 :(得分:0)

静态方法的设置未正确模拟

@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

被测试的对象实际上应该进行重构,以避免服务定位器出现anit模式/代码气味,并且应该通过构造函数注入遵循显式的依赖原则。

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);
    }
}

这样,主题类就可以正确执行其功能,这是真实的,

然后可以相应地重构测试

@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);

        //...
    }
}
相关问题