将数据预加载到 GAE 开发服务器数据存储中的验收测试

发布于 2024-10-13 01:51:19 字数 795 浏览 6 评论 0原文

在我的应用程序中,我有一组 DAO,我将它们注入到我的应用程序层中。对于我正在编写的验收测试,我想用数据预加载 dev_server 数据存储,因此我在 JUnit 测试中使用相同的 Spring 配置(使用 @ContextConfiguration 注释)将相关 DAO 的实例注入到我的测试中。当我实际去存储一些数据时,例如:

dao.add(entity)

我收到可怕的“没有为此线程注册 API 环境”。

Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
    ....

这可能是因为我的测试用例没有在 GAE application-web.xml 中读取应用程序详细信息(尽管我猜我可能真的错了);因此它不知道写入 dev_server 上运行的应用程序正在读取/写入的同一数据存储。

如何让我的测试“指向”与应用程序相同的数据存储?是否有一些“数据源”机制可以注入应用程序和测试中?有没有办法让我的测试强制数据存储 api 读取所需的配置?

In my application I have a set of of DAOs which I inject into my application layer. For an acceptance test I'm writing, I want to preload the dev_server datastore with data, so I use the same Spring config in my JUnit test (using the @ContextConfiguration annotation) to inject an instance of the relevant DAO into my test. When I actually go to store some data eg:

dao.add(entity)

I get the dreaded "No API environment is registered for this thread."

Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
    ....

This is probably because my test case hasn't read in the GAE application-web.xml with the app details (although I'm guessing here I could really be wrong); so it doesn't know to write to the same datastore that the app running on the dev_server is reading/writing to.

How can I get my test to "point" to the same datastore as the app? Is there some "datasource" mechanism that I can inject both into the app and the test? Is there a way to get my test to force the datastore api to read the needed config?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

傾旎 2024-10-20 01:51:19

此处是一个讨论如何进行单元测试的页面连接到开发数据存储的测试。这是您正在寻找的东西吗?基本上它讨论了两个类:LocalServiceTestHelper 和 LocalDatastoreServiceTestConfig,您可以使用它们来设置测试环境。虽然给出的示例是针对单元测试的,但我相信它也适用于您的情况。

然后,您可以配置诸如将开发数据存储写入磁盘还是仅保留在内存中(以加快测试速度)之类的内容。如果您希望这些数据与您的开发服务器位于同一位置,您可能需要对此进行调整,因为我认为默认值是“内存中”选项。如果您查看 javadoc 有一个“setBackingStoreLocation”方法,您可以在其中指向您想要的任何文件。

Here is a page that talks about how to do unit tests that connect to a dev datastore. Is this the kind of thing you're looking for? Basically it talks about two classes, LocalServiceTestHelper and LocalDatastoreServiceTestConfig that you can use to set up an environment for testing. While the example given is for unit tests, I believe it will also work for your situation.

You can then configure things like whether the dev datastore is written to disk or just kept in memory (for faster tests). If you want this data to go to the same place as your dev server, you will probably want to adjust this, as I think the default is the "in memory" option. If you look at the javadoc there is a "setBackingStoreLocation" method where you can point to whatever file you want.

落在眉间の轻吻 2024-10-20 01:51:19

我已经找到解决办法了!!!!

由于某种原因,测试数据存储的命名空间、AppID 和 AuthDomain 字段必须与 dev_server 的字段匹配,然后 dev_server 才能看到测试插入的实体。

您可以使用以下语句查看环境(dev_server 或测试代码)的值

System.out.println(NamespaceManager.get());
System.out.println(ApiProxy.getCurrentEnvironment().getAppId());
System.out.println(ApiProxy.getCurrentEnvironment().getAuthDomain());

在您的 LocalServiceTestHelper 实例(例如:gaeHelper)中,您可以设置测试环境的值

// the NamespaceManager is thread local.
NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());
gaeHelper.setEnvAppId(<the name of your app in appengine-web.xml>);
gaeHelper.setEnvAuthDomain("gmail.com");

然后 dev_server 将看到您的实体。但是,由于同步问题,如果测试在 dev_server 启动后写入数据存储,则 dev_server 将看不到它,除非可以强制它重新读取文件(我还没有弄清楚)。否则必须重新启动服务器。

I've found the solution!!!!

For some reason the Namespace, AppID and the AuthDomain fields of the test datastore have to match that of the dev_server, then the dev_server can see the entities inserted by the test.

You can see the values for the environment (dev_server or test code) with the following statements

System.out.println(NamespaceManager.get());
System.out.println(ApiProxy.getCurrentEnvironment().getAppId());
System.out.println(ApiProxy.getCurrentEnvironment().getAuthDomain());

In your instance of LocalServiceTestHelper (eg: gaeHelper), you can set the values for the test environment

// the NamespaceManager is thread local.
NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());
gaeHelper.setEnvAppId(<the name of your app in appengine-web.xml>);
gaeHelper.setEnvAuthDomain("gmail.com");

Then the dev_server will see your entities. However because of synchronisation issues, if the test writes to the datastore after the dev_server has been started the dev_server wont see it unless it can be forced to reread the file (which I haven't figured out yet). Else the server has to be restarted.

み青杉依旧 2024-10-20 01:51:19

我找到了一种解决方法,尽管它不是很好,因为每个测试方法都不会清理数据存储区,如文章 Java 本地单元测试,但是,每次运行 Test 类时,数据存储区都会开始清理,因此只要您对此小心的话,情况还不错。

问题是,当使用SpringJUnit4ClassRunner时,Spring环境是在@Before注解运行之前创建的,解决方案是使用@BeforeClass并为 LocalServiceTestHelper 使用静态变量,以便在设置 Spring 环境之前创建它们。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/spring/context-test.xml")
@Transactional
public class MyTest {


    @Inject
    private MyService myService;

    private static final LocalServiceTestHelper helper = 
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    @BeforeClass
    public static void beforeClass() {
        helper.setUp();
    }

    @AfterClass
    public static void afterClass() {
        helper.tearDown();
    }

如果有人有更好的解决方案,我将很高兴听到!

I've found a workaround, although it's not very nice because each test method doesn't clean up the Datastore, as explained in the article Local Unit Testing for Java, however, the Datastore starts clean each time the Test class is run, so it's not so bad, provided that you're careful about that.

The problem is, that when using SpringJUnit4ClassRunner, the spring environment is created before the @Before annotation can be run, the solution is use @BeforeClass and use a static variable for LocalServiceTestHelper, to have them created before the Spring Environment is set up.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/spring/context-test.xml")
@Transactional
public class MyTest {


    @Inject
    private MyService myService;

    private static final LocalServiceTestHelper helper = 
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    @BeforeClass
    public static void beforeClass() {
        helper.setUp();
    }

    @AfterClass
    public static void afterClass() {
        helper.tearDown();
    }

If anyone has a better solution, I'll be glad to hear!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文