如何防止服务的metaClass被覆盖 [英] How to keep service's metaClass from being overridden

查看:85
本文介绍了如何防止服务的metaClass被覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在集成测试中模拟对外部服务的调用,该服务在grails网络流中使用。该服务不在流或会话范围内,而是通过依赖项注入添加的,请参见这里

I'm trying to mock a call to an outside service in an integration test, the service is used in a grails webflow. The service isn't in flow or conversation scope, but is added via dependency injection see here.

我设法找到一种方法,可以通过使用ExpandoMetaClass替换其metaClass来覆盖服务。更改仅在单独运行测试时有效,如果在此测试之前运行了使用同一服务的另一个测试,则metaClass更改已消失。

I've managed to figure out a way to override a service via replacing it's metaClass using ExpandoMetaClass. The changes only work when the test is ran alone, if another test that uses that same service is ran before this test, the metaClass changes are gone.

覆盖metaClass:

Part that overrides the metaClass:

static {
    ExpandoMetaClass someService = new ExpandoMetaClass(Object, false)
    someService.invokeMethod = { String name, args ->
        def result = 'success'
        if(name.equals('accessAnotherSystem')
        {
            StackTraceUtils.sanitize(new Throwable()).stackTrace.each
            {
                if(it.methodName.equals('test_method_I_Want_failure_in')
                {
                    result = 'exception'
                }
            }
            return result
        }

        def validMethod = SomeService.metaClass.getMetaMethod(name, args)
        if (validMethod != null)
        {
            validMethod.invoke(delegate, args)
        }
        else
        {
            SomeService.metaClass.invokeMissingMethod(delegate, name, args)
        }
    }
    someService.initialize()
    SomeService.metaClass = someService
}

相关问题:如何在每次测试中更改类的metaClass

是否可以保留我对测试所做的更改,或者还有其他方法可以覆盖该服务。

Is there a way to keep my changes for the test, or is there some other way to override the service.

推荐答案

如果要在测试中覆盖该服务,则有一种更简单的方法。每个测试方法的案例。看一个例子:

There is a simpler way if you want to override the service in your test case per test method. Look at an example:

class SomeControllerSpec extends Specification {

    def someService

    void "test any external method for success response"() {
        given: "Mocked service method"
        someService.metaClass.accessAnotherSystem = { arg1, arg2 ->
            return "some success response"
        }

        when: "Any controller method is called which calls this service method"
        // Your action which calls that service method

        then: "Result will processed coming from mocked method"
        // Your code
    }
}

您可以对任何服务测试方法执行相同的操作。如果您想模拟要为其编写测试用例的相同服务的方法,那么就可以了。

You can do this same for any service test method. If you want to mock the method of same service for which you are writing test case then here yo go..

class SomeServiceSpec extends Specification {

    def someService

    void "test external method call"() {
        given: "Mocked service method"
        someService.metaClass.methodA = { arg1, arg2 ->
            return "some success response"
        }

        when: "A method is called which invokes the another method"
        // Your another service method which call the same method
        someService.methodB()    // Where methodB() invokes the methodA() internally in your code

        then: "Result will processed coming from mocked method"
        // Your code
    }
}

这篇关于如何防止服务的metaClass被覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆