首页 文章

Google App Engine数据存储区 - 测试查询失败

提问于
浏览
4

我目前正在尝试测试一段代码,该代码在放入新实体之前在数据存储区上运行查询,以确保不会创建重复项 . 我写的代码在应用程序的上下文中工作正常,但我为这些方法编写的测试失败了 . 似乎我无法通过测试包的上下文中的查询访问放入数据存储区的数据 .

一种可能性可能在于 goapp test 的输出,其中包括: Applying all pending transactions and saving the datastore . 在调用get和put方法之后打印出这一行(我用log语句验证了这一点) .

我尝试关闭上下文并为不同的操作创建一个新的上下文,但不幸的是,这也没有帮助 . 下面是一个简单的测试用例,它放入一个对象,然后在其上运行查询 . 任何帮助,将不胜感激 .

type Entity struct {
    Value string
}

func TestEntityQuery(t *testing.T) {
    c, err := aetest.NewContext(nil)
    if err != nil {
        t.Fatal(err)
    }
    defer c.Close()

    key := datastore.NewIncompleteKey(c, "Entity", nil)
    key, err = datastore.Put(c, key, &Entity{Value: "test"})
    if err != nil {
        t.Fatal(err)
    }

    q := datastore.NewQuery("Entity").Filter("Value =", "test")
    var entities []Entity
    keys, err := q.GetAll(c, &entities)
    if err != nil {
        t.Fatal(err)
    }
    if len(keys) == 0 {
        t.Error("No keys found in query")
    }
    if len(entities) == 0 {
        t.Error("No entities found in query")
    }
}

3 回答

  • 10

    您的测试代码没有任何问题 . 问题在于数据存储本身 . 人力资源数据存储区中的大多数查询都不是"immediately consistent",而是eventually consistent . 您可以在Datastore文档中阅读有关此内容的更多信息 .

    所以基本上发生的是你将一个实体放入数据存储区,而SDK的数据存储区“模拟”你在 生产环境 中可以观察到的延迟,所以如果你在那之后运行一个查询(这不是一个祖先的查询),那么查询结果将不包括您刚刚保存的新实体 .

    如果你在 datastore.Put() 和_1717850之间休息几秒钟,你会看到测试通过 . 试试吧 . 在我的测试中,它足以睡100毫秒,测试总是通过 . 但是在为这种情况编写测试时,请使用 StronglyConsistentDatastore: true 选项,如JonhGB的答案所示 .

    如果你使用Ancestor queries,你也会看到测试通过而没有睡眠,因为它们是strongly consistent .

  • 3

    这样做的方法是通过设置上下文来强制数据存储区强烈一致:

    c, err := aetest.NewContext(&aetest.Options{StronglyConsistentDatastore: true})
        if err != nil {
            t.Fatal(err)
        }
    

    现在,数据存储区不需要任何睡眠工作,这通常更快,更好 .


    Update: 这仅适用于通过 appengine/aetest 导入的旧aetest包 . 它不适用于使用 google.golang.org/appengine/aetest 导入的较新的aetest软件包 . App Engine已从使用 appengine.Context 更改为使用 context.Context ,因此测试包现在的工作方式完全不同 .

  • 5

    为了在最新版本的aetest中赞美@ JohnGB的答案,有更多步骤可以获得具有强一致性的上下文 . 首先创建一个实例,然后从该实例创建一个请求,您可以使用该请求生成一个上下文 .

    inst, err := aetest.NewInstance(
    &aetest.Options{StronglyConsistentDatastore: true})
    
    if err != nil {
        t.Fatal(err)
    }
    defer inst.Close()
    
    req, err := inst.NewRequest("GET", "/", nil)
    if err != nil {
        t.Fatal(err)
    }
    
    ctx := appengine.NewContext(req)
    

相关问题