Grails:如何使用非域抽象基类模拟域对象的属性

标签 grails spock

我有一个带有域类 Monster 的 grails 2.2.4 应用程序:

class Monster {
    int aggression
}

我可以像这样模拟和测试它:
import spock.lang.*
class MonsterSpec extends Specification {
    def "property mocks work"() {
        given:
        def m = Mock(Monster)
        m.aggression >> 5

        expect:
        m.aggression == 10
    }
}

最近我决定给它一个抽象基类(而不是域对象本身),这样我就可以在我的许多 Monster 之间共享方法实现。 - 类:
abstract class Entity {} // Not under /domain

class RefactoredMonster extends Entity {
    int aggression
}

但是随后一千个简单的测试都失败了,就像这样:
import spock.lang.*
class MonsterSpec extends Specification {
    def "property mocks work"() {
        given:
        def m = Mock(RefactoredMonster)
        m.aggression >> 10

        expect:
        m.getAggression() == 10 // This works

        and:
        m.aggression == 10 // This fails!  m.aggression is null!
    }
}

地球上发生了什么?如果我制作 Entity,问题就会消失具体的,但是当然我不能给任何东西补水Monster对象,因为 Hibernate 不知道如何处理 Entity (而且我不想让 Entity 成为域对象,尽管我想如果我真的必须这样做的话)。

我错过了什么?

最佳答案

问题是 GORM 期望父类(super class)是域类。

使用 Grails 2.2.4 所具有的 Groovy 2.0,您可以使用编译时 mixins向类添加方法。这允许在没有继承的情况下重用方法。
Entity可以保留为不是域类,但它必须是具体类。然后,而不是子类化,将其用作 mixin。

@Mixin(Entity)
class RefactoredMonster {
    int aggression
}

替代

正如您所说,由于您需要覆盖方法的能力,因此 Mixins 已出局。

从更高的层面来看,一个潜在的问题是架构/设计。继承旨在表示 is-a 关系(例如,狗是动物)。但是,当继承主要用作重用方法的一种方式时,它可能会导致……一团糟。

放弃继承并选择 has-a (委托(delegate))可能会更好。这将允许您重用行为并在需要时覆盖它。不幸的是,Groovy 2.0 不支持@Delegate。因此,以下示例将具有比 Groovy 2.4 中编码的相同内容更多的样板代码:
interface Flier {
    def fly();
}

class FlierImp {
    def fly() { "I'm fying! WOOT!" }
}

class RealDuck implements Flier {
    def flier

    RealDuck() {
        flier = new FlierImp() // Purposely not using injection
    }

    def fly() {
        flier.fly()
    }
}

class RubberDuck implements Flier {
    def fly() { "I don't fly" }
}

def duck = new RealDuck()
def rubberDuck = new RubberDuck()

assert duck.fly() == "I'm fying! WOOT!"
assert rubberDuck.fly() == "I don't fly"

在上面的示例中 RealDuckRubberDuck表示域类(这就是我不注入(inject)传单的原因)。飞行行为是由接口(interface)要求的,可以通过只实现该行为的类 (FlierImp) 或直接实现,如 RubberDuck 所示。 .

关于Grails:如何使用非域抽象基类模拟域对象的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34313244/

相关文章:

grails - 在Grails中创建条件

grails - 如果使用 grails asset-pipeline 插件,如何处理 css 中的图像位置?

Grails 多个数据源: org. springframework.beans.factory.NoUniqueBeanDefinitionException

android - TravisCI Android 构建仅在 CI 上失败,而非本地失败

java - Spring Rest 模板用 Spock 进行模拟

unit-testing - Spock spy 注册的 Groovy 方法调用太少(无)

grails - 具有多个多对多关联的GORM 'where criteria'

unit-testing - Spock 未检测到方法调用

grails - 你如何从你在 spock 中测试的类中模拟出方法

grails - 在Grails中实现 self 引用的一对多关系的最佳方法是什么?