Play!框架FakeApplication - 它实际上是做什么的?

6
我一直在查看StackOverflow上的一些帖子,以了解如何使用MYSQL数据库设置测试。我只想测试一些控制器方法,这需要一个测试数据库,并且需要一些数据才能返回有意义的结果。我想使用真实的MYSQL数据库,因为这是我将在生产中使用的,而且我已经读到MYSQL和Play提供的InMemory数据库之间存在相当多的差异。
在像这个这篇关于测试Play!应用程序的博客中,这些帖子展示了初始化一个FakeApplication对象的示例,并调用Helper.start(fakeApp)。
对于Helper.start(FakeApplication app),文档给出了以下描述:

启动一个新应用程序。

好的,但是调用start实际上会触发哪些进程,这会给我带来什么测试结果呢?
Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://localhost/testdb");
settings.put("db.default.user", "root");
settings.put("db.default.password", "");

app = Helpers.fakeApplication(settings);
Helpers.start(app);

我希望以上代码可以配置Ebean使用我的测试数据库,但当我尝试执行像 Ebean.save() 这样的方法时,会出现错误,说没有用Ebean注册默认的数据库。为了注册,我需要填写一个 ServerConfig 对象,并从 EbeanServerFactory 创建一个 EbeanServer。在这种情况下,将设置映射传递给 FakeApplication 对象是否有意义?再次提问,启动 FakeApplication 究竟有什么作用?它如何使用?
提前感谢您的帮助。

我也发现MySQL和H2(内存数据库)之间的差异太大,无法克服,并且这些演进无法编写成适用于两者的方式。 - jcreason
1个回答

4

我意识到你一年前就提出了这个问题,但是我自己花了很长时间才弄清楚,所以希望能在某个时候帮助到别人。有了正在运行的FakeApplication,您可以基本上做任何"activator run"之后可以做的事情,除了没有运行Web服务器(Netty)来提供请求服务。您可以测试您的控制器,就像这里所示,并调用访问数据库的方法。

实际上,在弄清楚这个问题的过程中,我参考了你提到的这两篇文章,另外还有这篇文章,它讨论了一些必须设置的特殊play魔术配置变量,您将在下面的示例中看到。

我创建了一个抽象的FakeApplicationTest类,我在Unit / Functional测试中使用它。我首先使用现有的application.conf文件,然后覆盖某些参数以针对不同的数据库进行测试。一旦FakeApplication启动,我读取所有演化并创建一个新的数据库来运行我的测试。

public abstract class FakeApplicationTest {

    protected static FakeApplication app;

    /**
     * Create a new FakeApplication using all our custom config vars that test against diff DB's
     *
     * @return
     */
    public static FakeApplication createFakeApp() {
        // grab the main application.conf file that is used to start up the Play application
        Config config = ConfigFactory.parseFile(new File("conf/application.conf"));

        // resolve all variables within this config file with other variables within itself
        config = ConfigFactory.load(config);

        // create a Configuration object out of this and then turn it into a Map to be modified
        Configuration configuration = new Configuration(config);
        Map<String, Object> fakeApplicationConf = Maps.newHashMap(configuration.asMap());

        // do some crazy stuff here because Play wants us to for config voodoo, see:
        // http://www.stupidjavatricks.com/2013/05/changing-play-2-db-configuration-at-runtime-beware-of-dragons/
        Configuration akka = configuration.getConfig("akka.actor.serialization-bindings");
        addValue(fakeApplicationConf, "akka.actor.serialization-bindings", null);
        addValue(fakeApplicationConf, "akka.actor.serialization-bindings.\"[B\"", akka.getString("\"[\"B"));
        addValue(fakeApplicationConf, "akka.actor.serialization-bindings.\"java.io.Serializable\"", akka.getString("\"java.io.Serializable\""));

        // point at a different test database
        addValue(fakeApplicationConf, "db.default.url", "jdbc:mysql://127.0.0.1/testdb");
        addValue(fakeApplicationConf, "db.default.user", "someuser");
        addValue(fakeApplicationConf, "db.default.password", "hunter2");

        // disable evolutions and just create the DB manually
        addValue(fakeApplicationConf, "evolutionplugin", "disabled");

        return Helpers.fakeApplication(fakeApplicationConf);
    }

    @BeforeClass
    public static void setUp() throws Exception {
        app = createFakeApp();

        // fire up the Fake Application!
        Helpers.start(app);

        // after we start up the application, create a database
        createCleanDb();
    }

    @AfterClass
    public static void tearDown() throws Exception {
        Helpers.stop(app);
    }

    ...
}

读取演变并按顺序应用它们有很多要注意的细节,但目前我将不涉及此内容。


谢谢您在这里发布!您能详细说明如何调用这个类吗?如果您有任何提示,我很想从命令行运行这个类。 - David
1
我们已经改变了这样做的方式,但我们只需让另一个JUnit测试类扩展此类,并在运行JUnit测试时,由于@BeforeClass注释,它会自动执行此操作。这里有另一个关于如何从命令行运行junit测试的问题:https://dev59.com/B3E95IYBdhLWcg3wm_Mu - jcreason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接