拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Mockitowhen()...then()方法没有回传预期的模拟物件(回传null),我做错了什么?

Mockitowhen()...then()方法没有回传预期的模拟物件(回传null),我做错了什么?

白鹭 - 2022-01-25 2179 0 0

运行我的测验时,以下何时/然后null在被测验的类中回传

    when(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)).thenReturn(producerSession);

NullPointerException是在建构式抛出。完整的测验类如下所示:

@RunWith(MockitoJUnitRunner.class)
public class HeartbeatTest {
    @Mock
    private static Connection connection;
    @Mock
    private static ActiveMQConnectionFactory mqConnectionFactory;
    @Mock
    private static ScheduledExecutorService scheduledExecutorService;
    @Mock
    private static MessageProducer heartbeatProducer;
    @Mock
    private static AbstractConfiguration config;
    @Mock
    private static ConnectionFactory cf;
    @Mock
    private static Session producerSession;

    @InjectMocks
    TestableHeartbeatImpl heartbeatImpl;

    @Test
    public void processHeartbeatSuccessfullyTest() throws JMSException {
        when(config.getModuleName()).thenReturn("testModule");
        when(config.getModuleQueue()).thenReturn("testqueue");
        when(config.getModuleId()).thenReturn("abcd1234");
        when(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)).thenReturn(producerSession);
        when(producerSession.createProducer(any(Queue.class))).thenReturn(heartbeatProducer);
        when(heartbeatImpl.createConnection(cf)).thenReturn(connection);
        heartbeatImpl.acknowledge(1000);
        verify(scheduledExecutorService.schedule(any(Runnable.class), anyLong(), any()), times(3))
                .isDone();
    }

    static class TestableHeartbeatImpl extends HeartbeatImpl {

        public TestableHeartbeatImpl() throws JMSException {
            super(config);
        }

       @Override
       protected Runnable createHeartbeatMessageRunnable(){
            return super.createHeartbeatMessageRunnable();
       }

        @Override
        protected ActiveMQConnectionFactory getActiveMQConnectionFactory(String artemisConnection){
            System.out.println("Calling overridden getActiveMQConnectionFactory");
            return mqConnectionFactory;
        }

        @Override
        protected Connection createConnection(ConnectionFactory cf){
            return connection;
        }
    }
}

被测验的类看起来像这样,producerSession没有注入模拟,因此在NullPointerException呼叫它的方法时会抛出:

public class HeartbeatImpl implements Heartbeat {
    private static final Logger logger = LogManager.getLogger(HeartbeatImpl.class);

    private final Session producerSession;
    private final MessageProducer heartbeatProducer;
    private final long timeoutPeriodMillis;
    private final long hearbeatPeriodMillis;
    private final AbstractConfiguration conf;
    private final String moduleName;
    private final Queue privateQueue;
    private final ScheduledExecutorService scheduledExecutorService;

    private ActiveMQConnectionFactory mqConnectionFactory;
    private Runnable heartbeatMessageRunnable;


    public HeartbeatImpl(AbstractConfiguration conf) throws JMSException {
        this.conf = conf;
        this.moduleName = conf.getModuleName();
        ConnectionFactory cf = createConnectionFactory(conf);
        Connection connection = createConnection(cf);
        producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        privateQueue = new ActiveMQQueue(conf.getModuleQueue()   ".private."   conf.getModuleId());
        logger.debug("creating heartbeat producer for {}", conf.getModuleQueue()   ".private."   conf.getModuleId());
        heartbeatProducer = producerSession.createProducer(privateQueue);
        timeoutPeriodMillis = conf.getHeartbeatTimeout();
        hearbeatPeriodMillis = conf.getHeartbeatPeriod();
        scheduledExecutorService = Executors.newScheduledThreadPool(1);
        logger.trace("Scheduling first heartbeat message");
        heartbeatMessageRunnable = createHeartbeatMessageRunnable();
        scheduledExecutorService.schedule(heartbeatMessageRunnable, hearbeatPeriodMillis, TimeUnit.MILLISECONDS);
    }

    @Override
    public void acknowledge(long sendTime) {
        long receiveTime = System.currentTimeMillis();
        logger.trace("Heartbeat received after {}ms", receiveTime - sendTime);
        ((HeartbeatMessageRunnable) heartbeatMessageRunnable).getScheduledFuture().cancel(true);
        heartbeatMessageRunnable = createHeartbeatMessageRunnable();
        logger.trace("scheduling heartbeat message");
        scheduledExecutorService.schedule(heartbeatMessageRunnable, hearbeatPeriodMillis, TimeUnit.MILLISECONDS);
    }

    @Override
    public void shutdown() {
        logger.info("Shutting down heartbeatService");
        scheduledExecutorService.shutdownNow();
        try {
            heartbeatProducer.close();
        } catch (JMSException e) {
            logger.error("Cannot shutdown heartbeatProducer", e);
        }
    }

    private ConnectionFactory createConnectionFactory(AbstractConfiguration conf) {
        String artemisConnection = conf.getArtemisConnection();
        ConnectionFactory cf = getActiveMQConnectionFactory(artemisConnection);
        logger.debug("Artemis connection correctly established: {}", artemisConnection);
        return cf;
    }

    protected ActiveMQConnectionFactory getActiveMQConnectionFactory(String artemisConnection) {
        if (mqConnectionFactory == null) {
            return new ActiveMQConnectionFactory(artemisConnection);
        } else {
            return mqConnectionFactory;
        }
    }

    protected Connection createConnection(ConnectionFactory cf) throws JMSException {
        return cf.createConnection(conf.getArtemisUsername(), conf.getArtemisPassword());
    }

    protected Runnable createHeartbeatMessageRunnable(){
        if (heartbeatMessageRunnable == null) {
            return new HeartbeatMessageRunnable();
        } else {
            return heartbeatMessageRunnable;
        }
    }

    // Below are the Runnable classes used by this service

    class HeartbeatMessageRunnable implements Runnable {
        private ScheduledFuture<?> scheduledFuture;

        @Override
        public void run() {
            try {
                TextMessage heartBeatMessage = producerSession.createTextMessage();
                heartBeatMessage.setStringProperty(PARAM_MODULE_NAME, moduleName);
                heartBeatMessage.setIntProperty(PARAM_SECURITY_LEVEL, 0);
                heartBeatMessage.setStringProperty(PARAM_ACTION, CMD_HEARTBEAT_ACK);
                heartBeatMessage.setLongProperty(PARAM_TIMESTAMP, System.currentTimeMillis());
                heartbeatProducer.send(heartBeatMessage);
                scheduledFuture = scheduledExecutorService.schedule(new HeartbeatShutdownRunnable(), timeoutPeriodMillis, TimeUnit.MILLISECONDS);
            } catch (JMSException e) {
                logger.error("An exception occurred when trying to send a heartbeat message", e);
            }
        }

        private ScheduledFuture<?> getScheduledFuture() {
            return scheduledFuture;
        }
    }

    static class HeartbeatShutdownRunnable implements Runnable {
        private final Logger logger = LogManager.getLogger(HeartbeatShutdownRunnable.class);

        @Override
        public void run() {
            logger.fatal("Heartbeat failed, shutting down module");
            System.exit(1);
        }
    }
}

我究竟做错了什么?

uj5u.com热心网友回复:

@InjectMocks在这里使用似乎是错误的。
在洗掉该注释并在测验本身中实体化类之后,我可以让事情正常进行。
这也意味着我不再需要属性和内部类是静态的。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *