【问题标题】:Unit testing a verticle deployment对 Verticle 部署进行单元测试
【发布时间】:2017-11-15 14:41:06
【问题描述】:

我有一个简单的 Verticle,它从属性文件中读取配置并加载到 vertx 配置中。我编写了一个单元测试来测试这个 Verticle 的部署,测试失败的可能原因是该位置的属性文件不可用。

当我运行测试时,无论我是否更改了属性文件名或路径,单元测试都会通过,并且处理程序说 Verticle 已成功部署。

我在这里做错了吗?下面是我的代码

import io.vertx.config.ConfigRetrieverOptions;
import io.vertx.config.ConfigStoreOptions;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.rxjava.config.ConfigRetriever;
import io.vertx.rxjava.core.AbstractVerticle;


/**
 * This is the main launcher verticle, the following operations will be executed in start() method of this verticle:
 * 1. Read configurations from application.properties file
 * 2. Deploy all other verticles in the application
 */
public class LauncherVerticle extends AbstractVerticle {


    @Override
    public void start() throws Exception {

        //set up configuration from the properties file
        ConfigStoreOptions fileStore = new ConfigStoreOptions()
                .setType("file")
                .setFormat("properties")
                .setConfig(new JsonObject().put("path", System.getProperty("vertex.config.path"));

        //create config retriever options add properties to filestore
        ConfigRetrieverOptions options = new ConfigRetrieverOptions().addStore(fileStore);
        ConfigRetriever configRetriever = ConfigRetriever.create(vertx, options);

        DeploymentOptions deploymentOptions = new DeploymentOptions();

        //Deploy verticles after the config has been loaded
        //The configurations are loaded into JsonConfig object
        //This JsonConfig object can be accessed in other verticles using the config() method.
        configRetriever.rxGetConfig().subscribe(s -> {

            //pass on the JsonConfig object to other verticles through deployment options
            deploymentOptions.setConfig(s);
            vertx.deployVerticle(AnotherVerticle.class.getName(), deploymentOptions);

        }, e -> {
            log.error("Failed to start application : " + e.getMessage(), e);
            try {
                stop();
            } catch (Exception e1) {
                log.error("Unable to stop vertx, terminate the process manually : "+e1.getMessage(), e1);
            }
        });
    }
}

这是我的单元测试

import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import io.vertx.rxjava.core.Vertx;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import rx.Single;


@RunWith(VertxUnitRunner.class)
public class LoadConfigurationTest {


    /**
     * Config should be loaded successfully
     *
     * @param context
     */
    @Test
    public void loadConfigTest(TestContext context) {
        /*
         * Set the system property "vertx.config.path" with value "application.properties"
         * This system property will be used in the Launcher verticle to read the config file
         */
        System.setProperty("vertx.config.path", "/opt/vertx/config/application.properties");

        //create vertx instance
        Vertx vertx = Vertx.vertx();

        Single<String> single = vertx.rxDeployVerticle(LauncherVerticle.class.getName());
        single.subscribe(s -> {
            vertx.rxUndeploy(s);
        }, e -> {
            Assert.fail(e.getMessage());
        });

    }

    /**
     * Test for negative use case - file not available in the specified location
     *
     * @param context
     */
    @Test
    public void loadConfigFailTest(TestContext context) {

         //set path = non existing path
        System.setProperty("vertx.config.path", "/non/existing/path/application.properties");

        //create vertx instance
        Vertx vertx = Vertx.vertx();

        Single single = vertx.rxDeployVerticle(LauncherVerticle.class.getName());

        single.subscribe(s -> {
            //not executing this statement
            Assert.fail("Was expecting error but Verticle deployed successfully");
        }, e -> {
            //not executing this statement either
            System.out.println("pass");
        });
    }
}

【问题讨论】:

    标签: java junit rx-java vert.x


    【解决方案1】:

    您能否在您的LauncherVerticle 中尝试以下代码?更改仅包括使用AbstractVerticles startFuture,这是一种处理配置加载和启动过程中几乎相同的一切的巧妙方法。

    public class LauncherVerticle extends AbstractVerticle {
    @Override
    public void start(Future<Void> startFuture) throws Exception {
            ConfigStoreOptions fileStore = new ConfigStoreOptions()
                    .setType("file")
                    .setFormat("properties")
                    .setConfig(new JsonObject().put("path", System.getProperty("vertex.config.path")));
    
            ConfigRetrieverOptions options = new ConfigRetrieverOptions().addStore(fileStore);
            ConfigRetriever configRetriever = ConfigRetriever.create(vertx, options);
    
            DeploymentOptions deploymentOptions = new DeploymentOptions();
            configRetriever.rxGetConfig().subscribe(s -> {
                        deploymentOptions.setConfig(s);
                        vertx.deployVerticle(AnotherVerticle.class.getName(),
                                deploymentOptions,
                                result -> startFuture.complete()
                        );
                    },
                    startFuture::fail
            );
        }
    }
    

    startFuture 那里,将帮助您控制垂直加载的状态。

    还请记住,@Constantine 处理测试的方式是最好的方式,使用 Async 来防止您的测试在没有实际断言的情况下通过。

    【讨论】:

      【解决方案2】:

      看起来你的verticle没有问题。但是,测试中有一些东西 - 没有考虑 Verticle 部署的异步性质。这些测试方法会立即完成,而不是等待 Verticle 部署,并且不会导致 AssertionError 的 JUnit 测试是通过测试。您必须使用 Async 显式发出完成信号。

      请在下面查看您的负面情况的示例:

      import io.vertx.ext.unit.Async;
      import io.vertx.ext.unit.TestContext;
      import io.vertx.ext.unit.junit.RunTestOnContext;
      import io.vertx.ext.unit.junit.VertxUnitRunner;
      import io.vertx.rxjava.core.Vertx;
      import org.junit.Rule;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      
      @RunWith(VertxUnitRunner.class)
      public class LoadConfigurationTest {
      
          @Rule
          public RunTestOnContext runTestOnContextRule = new RunTestOnContext();
      
          @Test
          public void testConfigLoading_shouldFail_whenConfigDoesNotExist(TestContext context) {
              // create an Async instance that controls the completion of the test
              Async async = context.async();
      
              // set non existing path
              System.setProperty("vertx.config.path", "/non/existing/path/application.properties");
      
              // take vertx instance and wrap it with rx-ified version
              Vertx vertx = Vertx.newInstance(runTestOnContextRule.vertx());
      
              vertx.rxDeployVerticle(LauncherVerticle.class.getName()).subscribe(s -> {
                  context.fail("Was expecting error but Verticle deployed successfully"); // failure
              }, e -> {
                  async.complete(); // success
              });
          }
      }
      

      另外请注意,您可以从RunTestOnContext 规则中获取Vertx 实例(如上面的sn-p)。

      【讨论】:

      • 感谢康斯坦丁,但使用来自RunTestOnContext 的 vertx 实例不会给出我需要的 vertx 的 rxified 版本。
      • 很高兴有帮助。 RunTestOnContext 中的 Vertx 实例确实没有被 rxified。这就是为什么我用io.vertx.rxjava.core.Vertx.newInstance(runTestOnContextRule.vertx()) 包装它。但是,您可以简单地在测试中使用非 rxified 版本,因为 rxified 版本不是不同的实现,而只是 io.vertx.core.Vertx 功能的包装器。
      • 我在 vertx 邮件中添加了对同一问题的回复的链接:groups.google.com/forum/#!topic/vertx/ccCLBWVAcX0
      猜你喜欢
      • 1970-01-01
      • 2012-01-08
      • 2012-05-14
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多