聊聊artemis对junit的支持

  • 2020 年 1 月 20 日
  • 笔记

本文主要研究一下artemis对junit的支持

TestRule

junit-4.12-sources.jar!/org/junit/rules/TestRule.java

public interface TestRule {      /**       * Modifies the method-running {@link Statement} to implement this       * test-running rule.       *       * @param base The {@link Statement} to be modified       * @param description A {@link Description} of the test implemented in {@code base}       * @return a new statement, which may be the same as {@code base},       *         a wrapper around {@code base}, or a completely new Statement.       */      Statement apply(Statement base, Description description);  }
  • TestRule定义了apply方法用于修改并返回Statement

ExternalResource

junit-4.12-sources.jar!/org/junit/rules/ExternalResource.java

public abstract class ExternalResource implements TestRule {      public Statement apply(Statement base, Description description) {          return statement(base);      }  ​      private Statement statement(final Statement base) {          return new Statement() {              @Override              public void evaluate() throws Throwable {                  before();                  try {                      base.evaluate();                  } finally {                      after();                  }              }          };      }  ​      /**       * Override to set up your specific external resource.       *       * @throws Throwable if setup fails (which will disable {@code after}       */      protected void before() throws Throwable {          // do nothing      }  ​      /**       * Override to tear down your specific external resource.       */      protected void after() {          // do nothing      }  }
  • ExternalResource声明实现了TestRule接口,其apply方法创建一个匿名Statement并重写其evaluate方法,该方法先执行before,在执行base.evaluate(),最后执行after

EmbeddedActiveMQResource

activemq-artemis-2.11.0/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java

public class EmbeddedActiveMQResource extends ExternalResource {  ​      //......  ​     /**      * Invoked by JUnit to setup the resource - start the embedded ActiveMQ Artemis server      */     @Override     protected void before() throws Throwable {        log.info("Starting {}: {}", this.getClass().getSimpleName(), getServerName());  ​        this.start();  ​        super.before();     }  ​     /**      * Invoked by JUnit to tear down the resource - stops the embedded ActiveMQ Artemis server      */     @Override     protected void after() {        log.info("Stopping {}: {}", this.getClass().getSimpleName(), getServerName());  ​        this.stop();  ​        super.after();     }  ​     public void start() {        try {           server.start();        } catch (Exception ex) {           throw new RuntimeException(String.format("Exception encountered starting %s: %s", server.getClass().getName(), this.getServerName()), ex);        }  ​        configuration = server.getActiveMQServer().getConfiguration();     }  ​     public void stop() {        if (internalClient != null) {           internalClient.stop();           internalClient = null;        }  ​        if (server != null) {           try {              server.stop();           } catch (Exception ex) {              log.warn(String.format("Exception encountered stopping %s: %s", server.getClass().getSimpleName(), this.getServerName()), ex);           }        }     }  ​      //......  ​  }
  • EmbeddedActiveMQResource继承了ExternalResource,并覆盖了before及after方法;before执行的是start方法,after执行的是stop方法;start方法主要是执行EmbeddedActiveMQ.start;stop方法主要是执行InternalClient.stop以及EmbeddedActiveMQ.stop

AbstractActiveMQClientResource

activemq-artemis-2.11.0/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientResource.java

public abstract class AbstractActiveMQClientResource extends ExternalResource {  ​      //......  ​     @Override     protected void before() throws Throwable {        super.before();        start();     }  ​     @Override     protected void after() {        stop();        super.after();     }  ​     void start() {        log.info("Starting {}", this.getClass().getSimpleName());        try {           sessionFactory = serverLocator.createSessionFactory();           session = sessionFactory.createSession(username, password, false, true, true, serverLocator.isPreAcknowledge(), serverLocator.getAckBatchSize());        } catch (RuntimeException runtimeEx) {           throw runtimeEx;        } catch (Exception ex) {           throw new ActiveMQClientResourceException(String.format("%s initialisation failure", this.getClass().getSimpleName()), ex);        }  ​        createClient();  ​        try {           session.start();        } catch (ActiveMQException amqEx) {           throw new ActiveMQClientResourceException(String.format("%s startup failure", this.getClass().getSimpleName()), amqEx);        }     }  ​     void stop() {        stopClient();        if (session != null) {           try {              session.close();           } catch (ActiveMQException amqEx) {              log.warn("ActiveMQException encountered closing InternalClient ClientSession - ignoring", amqEx);           } finally {              session = null;           }        }        if (sessionFactory != null) {           sessionFactory.close();           sessionFactory = null;        }        if (serverLocator != null) {           serverLocator.close();           serverLocator = null;        }  ​     }  ​     protected abstract void createClient();  ​     protected abstract void stopClient();  ​      //......  ​  }
  • AbstractActiveMQClientResource继承了ExternalResource,其before方法执行的是start方法,其after方法执行的是stop方法;start方法会创建session,执行createClient,最后执行session.start;stop方法执行stopClient、session.close、sessionFactory.close、serverLocator.close;它定义了createClient、stopClient抽象方法需要子类去实现

ActiveMQProducerResource

activemq-artemis-2.11.0/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java

public class ActiveMQProducerResource extends AbstractActiveMQClientResource {  ​      //......  ​     @Override     protected void createClient() {        try {           if (!session.addressQuery(address).isExists() && autoCreateQueue) {              log.warn("{}: queue does not exist - creating queue: address = {}, name = {}", this.getClass().getSimpleName(), address.toString(), address.toString());              session.createQueue(address, address);           }           producer = session.createProducer(address);        } catch (ActiveMQException amqEx) {           throw new ActiveMQClientResourceException(String.format("Error creating producer for address %s", address.toString()), amqEx);        }     }  ​     @Override     protected void stopClient() {        if (producer != null) {           try {              producer.close();           } catch (ActiveMQException amqEx) {              log.warn("ActiveMQException encountered closing InternalClient ClientProducer - ignoring", amqEx);           } finally {              producer = null;           }        }     }  ​      //......  }
  • ActiveMQProducerResource继承了AbstractActiveMQClientResource;其createClient方法执行session.createProducer(address);其stopClient方法执行producer.close()

ActiveMQConsumerResource

activemq-artemis-2.11.0/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java

public class ActiveMQConsumerResource extends AbstractActiveMQClientResource {        //......  ​     @Override     protected void createClient() {        boolean browseOnly = false;        try {           if (!session.queueQuery(queueName).isExists() && autoCreateQueue) {              log.warn("{}: queue does not exist - creating queue: address = {}, name = {}", this.getClass().getSimpleName(), queueName.toString(), queueName.toString());              session.createAddress(queueName, RoutingType.MULTICAST, true);              session.createQueue(queueName, queueName);           }           consumer = session.createConsumer(queueName, browseOnly);        } catch (ActiveMQException amqEx) {           throw new ActiveMQClientResourceException(String.format("Error creating consumer for queueName %s", queueName.toString()), amqEx);        }     }  ​     @Override     protected void stopClient() {        if (consumer != null) {           try {              consumer.close();           } catch (ActiveMQException amqEx) {              log.warn("Exception encountered closing consumer - ignoring", amqEx);           } finally {              consumer = null;           }        }     }  ​      //......  ​  }
  • ActiveMQConsumerResource继承了AbstractActiveMQClientResource,其createClient方法执行的是session.createConsumer(queueName, browseOnly);其stopClient方法执行的是consumer.close()

小结

artemis对junit的ExternalResource提供了扩展,对于server端提供了EmbeddedActiveMQResource,对于client端提供了AbstractActiveMQClientResource(ActiveMQProducerResource、ActiveMQConsumerResource)

doc