首页 > 解决方案 > 延迟测试清理的行为因我调用它的位置而异

问题描述

我有一个遵循以下结构的测试:

var testInstance aetest.Instance // initialized by a TestMain

TestThing(t *testing.T) {
    defer cleanupGoogleDatastore(t, testInstance)

    // insert basic test fixtures

    // insert some new records here

    // test assertions, etc.
}

cleanupGoogleDatastore方法只是为特定实体类型的所有实体运行数据存储查询,然后将它们一一删除。来源:

func cleanupGoogleDatastore(t *testing.T, testInstance aetest.Instance) {
    q := datastore.NewQuery("Order")
    ctx := GetContext(t, testInstance)
    scanner := q.Run(ctx)
    for {
        var o model.Order
        key, err := scanner.Next(&o)
        if err == datastore.Done {
            return
        }
        if err != nil {
            t.Fatal(err.Error())
        }
        err = datastore.Delete(ctx, key)
        if err != nil {
            t.Fatal(err.Error())
        }
    }
}

我遇到的问题是,在“基本测试装置”之后插入的记录不会被这个延迟清理语句删除。

如果我将此测试功能更改为如下所示:

var testInstance aetest.Instance // initialized by a TestMain  

TestThing(t *testing.T) {
    defer cleanupGoogleDatastore(t, testInstance)

    // insert basic test fixtures

    // insert some new records here

    defer cleanupGoogleDatastore(t, testInstance)
    // note that I have to call it TWICE - just moving it here is not enough.

    // test assertions, etc.
}

那么新创建的记录也会在测试结束时被删除。我的理解是,deferred函数只是在原始函数范围的末尾被调用,这意味着在测试结束之前不会构造和运行查询,但这里似乎并非如此。似乎在调用 defer 语句然后在测试结束时执行查询时正在构造查询。

我已经尝试过cleanupGoogleDatastore关闭(例如defer func() { cleanupGoogleDatastore(t, testInstance }(),这并没有改变任何东西。

我怀疑这是在我调用 defer 而不是在调用函数时评估函数参数的情况,但是由于两者t都是testInstance指针而不是直接值,我不确定这是如何发生的。没有其他证据表明这两个值发生了变化。在不同的逻辑评估点打印出两个结构的字段并没有揭示任何新内容。

这里发生了什么?

标签: google-app-enginegogoogle-cloud-datastore

解决方案


事实证明,这是本地 App Engine Datastore 存根的故意属性,默认情况下会返回弱一致的查询。我能够通过将代码更改为cleanupGoogleDatastore依赖祖先查询来解决此问题,该祖先查询成功找到并删除了所有实体。另一种方法是将 aetest.Instance 设置为强一致,但我不想在我的所有测试中强制执行强一致的行为 - 只是这个。


推荐阅读