4

概括

使用 appengine 的 High Replication Datastore 设置单元测试时,我看到了一些奇怪的行为。

我在下面放了一个完整的例子。问题是来自一个测试用例的持久化对象可用于后面的测试用例,但只有在后面的测试用例在事务中检索它时才可用。据我了解,tearDown 方法应该完全清除数据存储。

我认为我的设置有问题,或者我遗漏了一些重要的东西。请帮忙。

具体问题

给定下面的代码,为什么输出如下?(特别是我加粗的最后一行)

2013 年 9 月 17 日 20:41:35 org.datanucleus.PersistenceConfiguration setProperty

信息:属性 datanucleus.appengine.singletonPMFForName 未知 - 将被忽略

2013 年 9 月 17 日 20:41:36 com.google.appengine.datanucleus.MetaDataValidator 验证

信息:为 com.test.Thing 执行特定于 appengine 的元数据验证

2013 年 9 月 17 日 20:41:36 com.google.appengine.datanucleus.MetaDataValidator 验证

信息:已完成对 com.test.Thing 执行特定于 appengine 的元数据验证

2013 年 9 月 17 日 20:41:36 com.google.appengine.api.datastore.dev.LocalDatastoreService 初始化

信息:本地数据存储已初始化:类型:主/从存储:内存中 17-Sep-2013 20:41:36 com.google.appengine.api.datastore.dev.LocalDatastoreService init

信息:本地数据存储已初始化:类型:主/从存储:内存中

[外部交易] 这会正确执行。

[INSIDE TRANSACTION] 这不应该被执行。东西:项目

我的评论

除非我正在做一些非常愚蠢的事情,这并非不可能,否则似乎在第一个测试用例中保留的项目仍然可用于第二个测试用例中的事务。

第二个测试用例尝试在事务之外获取对象ById,并正确抛出异常。

然后它在事务中尝试相同的操作并检索一个对象,我认为该对象只能是早期测试用例中保留的对象。

为什么是这样?我做错了什么?首先十分感谢。

复制问题的代码

我在 Eclipse 中创建了一个新的 Web 应用程序项目,并将此屏幕截图中显示的类和 jar 添加到其中:

包资源管理器的屏幕截图

PMF 类如下所示:

package com.test;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {

    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF() {}

    public static PMF getInstance() {
        if (null == _instance) {
            _instance = new PMF();
        }
        return _instance;
    }

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }

    private static PMF _instance;
}

类事物看起来像这样:

package com.test;

import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@PersistenceCapable
public class Thing {

    public Thing(String item) {
        this.item = item;
        this.key = makeKey(item);
    }


    public static Key makeKey(String item) {
        return KeyFactory.createKey("Thing", item);
    }

    public String getId() {
        if (null == key) {
            return null;
        }
        return KeyFactory.keyToString(key);
    }

    public String getItem() {
        return item;
    }

    public String toString() {
        return "THING:" + item;
    }

    @PrimaryKey
    @Persistent
    private Key key;
    @Persistent
    private String item;
}

最后,TestDatastore 类如下所示:

package com.test;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;

import junit.framework.TestCase;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;

public class TestDatastore extends TestCase {

    @Override
    public void setUp() {
        helper.setUp(); 
    }

    @Override
    public void tearDown() {
        helper.tearDown();
    }

    public void testCreateThing() {

        String item = "item";
        Thing thing = new Thing(item);

        PersistenceManager pm = PMF.get().getPersistenceManager();
        Thing persisted = pm.makePersistent(thing);
        Thing result = pm.getObjectById(Thing.class, persisted.getId());

        assertEquals(item, result.getItem());
    }

    public void testThingDoesntExist() {

        String item = "item";
        Thing thing = new Thing(item);

        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try {
            Thing testThing = pm.getObjectById(Thing.class, Thing.makeKey(thing.getItem()));
        } catch (Exception e) {
            System.out.println("[OUTSIDE TRANSACTION] This correctly gets executed.");
        }

        try {
            tx.begin();
            Thing testThing = pm.getObjectById(Thing.class, Thing.makeKey(thing.getItem()));
            System.out.println("[INSIDE TRANSACTION] This should not be executed. " + testThing);
            tx.commit();
        } catch (Exception e) {
            System.out.println("This doesn't get executed, but it should");
        }
    }

    private final LocalServiceTestHelper helper = 
            new LocalServiceTestHelper(
                    new LocalDatastoreServiceTestConfig()
                    .setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
}
4

1 回答 1

0

那看起来确实很奇怪。但是,有两件事引起了我的注意:

  1. 您使用 setDefaultHighRepJobPolicyUnappliedJobPercentage(100)。那是故意的吗?也许将其设置为0?可能不是它。

  2. 在 Google JDO 示例中,他们似乎一直关闭 pm。尝试这样做(尤其是在 testCreateThing() 中):

    最后 { pm.close(); }

于 2014-11-11T19:30:44.863 回答