2015-03-02 60 views
1

我一直试图弄清楚这2天现在,我真的卡住和沮丧。我有一个域对象和一个正在用于自定义验证的服务。该域看起来像这样:Grails 2.4.4:如何模拟域内的瞬态服务?

class Llama { 
String name 
transient myFetcherService 

static transients = [ 
      'myFetcherService' 
    ] 

static constraints = { 
     name validator: { val, obj -> 
      if (obj.nameExists(val) == true) { 
       //return some error here. 
      } 
     } 
    } 

protected boolean nameExists(String name) { 
     List<Llama> llamasList = myFetcherService.fetchExistingLlamasByName(name) 

     if (llamasList.isEmpty()) { 
      return false 
     } 

     return true 
    } 
} 

现在,我有另一个服务,它只保存一个美洲驼对象的列表。它看起来像这样:

class LlamaFactoryService { 

    public void createLlamas(List<String> llamaNames) { 
    llamaNames.each { name -> 
     new Llama(name: name).save() 
    } 
    } 

} 

在我的测试。我不断收到此错误:

Failure: createLlamas should create Llammas (com.myLlamaProject.LlamaFactoryServiceSpec) 
| java.lang.NullPointerException: Cannot invoke method myFetcherService on null object 

我不明白。在我的测试中,在“给定”部分为服务添加了一个metaClass。当它试图保存时,它告诉服务是空的。这是我的测试是什么样子:

given: 
def myFetcherService = mockFor(MyFetcherService) 
myFetcherService.demand.fetchExistingLlamasByName {def name -> return []} 
Llama.metaClass.myFetcherService = myFetcherService.createMock() 

when: 
service.createLlamas(['Pablo','Juan','Carlos']) 

then: 
//some validations here.... 

我的方法nameExists()喜欢使用的metaClass也尝试:

Llama.metaClass.myFetcherService = { def name -> false } 

,但它给了我同样的NullPointerException异常,如上图所示。有人能指出我正确的方向吗?我有点卡住了。 :(

预先感谢阅读和帮助。

+0

无论是单元还是集成测试,在这里添加相关标签。 – Abs 2015-03-02 18:00:57

+0

这是一个单元测试..谢谢 – CancerMan 2015-03-02 18:10:22

回答

0

您使用单元测试和单元测试的一般规则是,豆类一般不为您创建,所以你需要注入。他们自己

(代码编辑,以反映我误解了问题的事实) 我想你想测试模式是这样的:

given: 
def mockMyFetcherService = Mock(MyFetcherService) // create the mock 
Llama.metaClass.getMyFetcherService = { mockMyFetcherService } // inject the dependency 
def returnList = [] // let's just define this here and you can re-use this pattern in other tests more easily 

when: 
service.createLlamas(['Pablo','Juan','Carlos']) 

then: 
// tell Spock what you expect to have happen with your Mock - return the List you defined above 
3 * mockFetcherService.fetchExistingLlamasByName(_) >> returnList 

如果服务注入到元类不起作用(suggested here),你总是可以尝试在单元测试中使用defineBeans {}闭包(http://www.block-consult.com/blog/2011/08/17/inject-spring-security-service-into-domain-class-for-controller-unit-testing/)。

因此,你可以尝试:

defineBeans { 
    myFetcherService(MockMyFetcherService) 
} 

其中MockMyFetcherService设在限定测试同一个文件中定义。这是方法followed here

有关更多Spock交互的示例,请参见here

如果您使用Grails 2.4.3或更低版本,您需要将CGLIB放在BuildConfig.groovy中,但我看到here它已经在2.4.4中为您完成了,因此您应该可以使用Mock(classname)

+0

也在2.3.11工程。 – bassmartin 2015-03-03 01:18:26

+0

因此,我在使用域的服务中注入MyFetcherService?不在MyFetcherService所在的域中?从来没有想过...我使用的是grails 2.4.4。我会试试这个。感谢您的回应。 – CancerMan 2015-03-04 08:12:31

+0

不工作的人。 myFetcherService在域中使用,不在服务中使用。我有一个.MissingPropertyException:没有这样的属性:myFetcherService类LlamaFactoryService。:\ – CancerMan 2015-03-04 09:20:29