【问题标题】:How to implement instance behaviour (for testing) in Cuis/Squeak/Pharo?如何在 Cuis/Squeak/Pharo 中实现实例行为(用于测试)?
【发布时间】:2017-01-03 18:03:43
【问题描述】:

我已经实现了一些 ExternalStrctures(作为“FFI 工作”的一部分),对于其中一些我想实现最终化以回收外部内存。

我正在尝试为此编写一些测试,并认为了解#finalize 是否被调用的一个好方法是更改​​我用于测试的特定实例的行为。如果可能的话,我宁愿不要用支持测试的代码来污染实现。

我相信模拟特定方法和更改特定实例行为通常是一个很好的测试工具。

我知道这在其他方言中是可能的,并且我过去在 Squeak 中使用 #doesNotUnderstand 自己实现了它,但我想知道是否有更简洁的方法,可能受 VM 支持。

有没有办法改变特定实例在 Cuis/Squeak/Pharo 中回答特定消息的方式?

【问题讨论】:

    标签: smalltalk pharo squeak


    【解决方案1】:

    卢西亚诺举了一个很好的例子:

    EllipseMorph 复制编译:'defaultColor ^Color red';新 :: openInWorld

    邮件线程在这里: http://cuis-smalltalk.org/pipermail/cuis-dev_cuis-smalltalk.org/2016-March/000458.html

    【讨论】:

    • 不错。但请注意,这使用了终结,@gera 需要它来进行 测试 终结。
    • 不,它不使用终结。
    • 啊!出色的。我认为它确实可以摆脱复制的课程。
    • 当实例被收集时,该类才开始。实例是对复制类的唯一引用。卢西亚诺的把戏太棒了。
    • 非常好!感谢分享!
    【解决方案2】:

    在处理完问题后,我决定进行端到端测试,实际验证资源(在我的情况下为内存)是否已恢复到系统。我没有使用实例行为,尽管 Luciano 和 Juan 的解决方案(在评论中)非常有趣。这是我用于测试的代码:

    testFinalizationReleasesExternalMemory
        " WeakArray restartFinalizationProcess "
        | handles |
    
        handles := (1 to: 11) collect: [:i |
            Smalltalk garbageCollect.
            APIStatus create getHandle].
    
        self assert: (handles asSet size) < 11.
    

    在示例中,#create 使用 FFI 调用对分配内存并返回指针的外部函数(名称 create 来自外部 API):

    create
        | answer |
        answer := ExternalAPI current createStatus.
        self finalizationRegistry add: answer.
        ^ answer
    

    ExternalAPI 这里是 FFI 接口,#createStatus 是为 APIStatus 分配内存并返回指向它的指针的 API 调用。

    在完成时,我调用恢复内存的 API:

    delete
        self finalizationRegistry remove: self ifAbsent: [].
        self library deleteStatus: self.
        handle := nil.
    

    #deleteStatus: 又是释放内存的 API 调用。

    测试假设外部库在内存空闲后重用内存,特别是当新分配的块与前一个块具有相同大小时。这在今天的大多数情况下都是正确的,但如果不是这样,我希望看到这个测试失败,至少只是为了学习新东西。

    测试分配 11 个外部结构,保存它们的指针,让终结机制在分配下一个之前释放每个的内存,然后比较是否有任何指针重复。我不知道为什么我决定使用 10 个指针作为一个好数字,只要 2 个就足够了,但是内存分配算法有时很棘手。

    【讨论】:

    • 我建议在 Object 中添加两个方法,用于在 finalizationRegistry 中添加/删除实例,因此您只需要发送一元消息,例如 #useFinalization/#ingoreFinalization 等。
    • 谢谢!我实现了它们:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    相关资源
    最近更新 更多