如何模拟从控制器测试类注入域类的服务?

Posted

技术标签:

【中文标题】如何模拟从控制器测试类注入域类的服务?【英文标题】:How to mock a service injected in a domain class from a Controller Test Class? 【发布时间】:2012-05-03 18:50:03 【问题描述】:

我有一个域类,它扩展了一个注入spring security core plugin 服务的抽象类。

class Extra extends WithOwner 
    String name


abstract class WithOwner 
    transient springSecurityService
    User user

    def getCurrentUser() 
        return springSecurityService.currentUser
    

    def beforeValidate() 
        if(!user) 
             user = getCurrentUser()
        
    

    Boolean isLoggedUserTheOwner()
        return (user?.id == getCurrentUser()?.id)
    

我想实现一个控制器测试。

@TestFor(ExtraController)
@Mock([Extra, User, UserRole, Role])
class ExtraControllerTests 

    void testEdit() 
        def utils = new TestUtils()
        def user1 = utils.saveUser1()

        populateValidParams(params)
        def extra = new Extra(params)
        extra.user = user1
        assert extra.save() != null

        params.id = extra.id


        def model = controller.edit() // Line 69
        assert model.extraInstance == extra
    

如果我运行上述测试,我会得到:

test-app ExtraController.testEdit --unit --echoOut |运行 1 个单元测试... 1 of 1 --testEdit 的输出-- |失败:testEdit(com.softamo.movi​​lrural.ExtraControllerTests) | java.lang.NullPointerException:无法在空对象上获取属性“currentUser” 在 com.softamo.movi​​lrural.WithOwner.getCurrentUser(WithOwner.groovy:8) 在 com.softamo.movi​​lrural.WithOwner.isLoggedUserTheOwner(WithOwner.groovy:18) 在 com.softamo.movi​​lrural.ExtraController.edit(ExtraController.groovy:39) 在 com.softamo.movi​​lrural.ExtraControllerTests.testEdit(ExtraControllerTests.groovy:69) |完成 1 个单元测试,1 个在 853 毫秒内失败

我尝试过像这样模拟安全服务但没有成功:

Extra.metaClass.springSecurityService = new MockSpringSecurityService(user1)

甚至模拟方法

Extra.metaClass.getCurrentUser =  return user1 

知道如何解决这个问题。

【问题讨论】:

您好!我遇到了同样的问题。您是否为您的问题制定了解决方案?或者,也许您可​​以在没有单元测试自动装配的情况下在域对象中注入服务? 这个问题好运吗?,面临同样的问题。 【参考方案1】:

Grails 2.x 支持使用“defineBeans”闭包为测试环境定义 spring bean。 它支持控制器等中的依赖注入,我不确定它是否也适用于域对象。理论上它应该在域对象/控制器/服务之间保持一致

请参阅 http://grails.org/doc/latest/guide/single.html#testing -“测试 Spring Beans”部分。

【讨论】:

我试过这个,但不起作用。不知道如何为域类设置它。 defineBeans springSecurityService(new MockSpringSecurityService(user1)) 定义spring bean的时候不需要new MockSpringSecurityService(),只需springSecurityService(MockSpringSecurityService)【参考方案2】:

这应该可行:

controller.springSecurityService = new SpringSecurityService()

如果你想在这个服务中模拟 getCurrentUser 方法:

controller.springSecurityService.metaClass.getCurrentUser =  -> return user1 

我不确定你是否可以在上面的一行中省略->,所以测试一下。如果您想在使用后或另一个测试用例之前清除此模拟方法,请使用:

controller.springSecutiryService.metaClass = null

【讨论】:

这解释了如何将服务注入控制器,他的问题是如何在域对象中模拟服务。 为了记录,您可以省略->并将其简化为getCurrentUser = user1 【参考方案3】:

我发现了一篇关于这个问题的好文章:Inject springSecurityService Into Grails Domain Class for Controller Unit Testing

【讨论】:

以上是关于如何模拟从控制器测试类注入域类的服务?的主要内容,如果未能解决你的问题,请参考以下文章

在测试控制器方法时,Spring MVC 4.2.6 版似乎没有将模拟服务注入控制器

如何提供模拟实体管理器来测试服务类?

c#依赖注入和控制反转的书籍

将模拟类注入方法以单元测试方法

PHPUnit 模拟一个抽象类的所有方法

如何在 Spring Boot 中将属性注入测试类?