【问题标题】:Deferred test cleanup behaves differently based on where I invoke it延迟测试清理的行为因我调用它的位置而异
【发布时间】:2018-05-26 20:58:45
【问题描述】:

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

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 而不是在调用函数时评估函数参数的情况,但由于 ttestInstance 都是指针而不是直接值我'我不确定这是怎么发生的。没有其他证据表明这两个值发生了变化。在不同的逻辑评估点打印出两个结构的字段并没有揭示任何新内容。

这是怎么回事?

【问题讨论】:

  • 这是你的清理函数的实际签名还是你传递一些参数给它?
  • 还是定义在非指针值上的方法?
  • @mkopriva 这不是实际的签名。实际签名采用 *testing.T 和 aetest.Instance。我更新了代码示例以更准确地反映实际代码。
  • @mkopriva 暗示的是函数参数是在defer 处确定的,而不是在执行时确定的。一切都是按值传递的,因此在defer 处创建一个副本,以供最终执行时使用。 (尽管不要混淆指针,指针值被复制,但它仍然指向反映变化的同一事物)请参阅示例以了解一些陷阱。 play.golang.org/p/2LoG_90OiSM
  • @Venantius 一个简单的解决方法是将清理函数的调用包装到一个闭包中,这样在执行延迟函数时就会评估参数。 defer func() { cleanup(arg1, arg2) }()

标签: google-app-engine go google-cloud-datastore


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    • 2019-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    相关资源
    最近更新 更多