【问题标题】:Groovy: How to mock imported class and its methodsGroovy:如何模拟导入的类及其方法
【发布时间】:2021-05-02 21:53:55
【问题描述】:

我有 Groovy PSL 项目,我想为调用外部类的代码添加测试。 所以,例如,我想模拟这个DeploymentMetrics 类和它的方法,所以它不会调用真正的类。我只想验证它是否被调用。

CICDTest.groovy

import com.lesfurets.jenkins.unit.BaseRegressionTest
import org.junit.Before
import org.junit.Test

class CICDTest extends BaseRegressionTest {
    def serviceVersion = "12345rds234"
    String team = "TEAM"
    String service = "SERVICE"
    String deployEnv = "Development"
    String deployType = "App Code Deployment"
    String deployReason = "Routing Change"

    @Override
    @Before
    void setUp() throws Exception {
        super.setUp()
        callStackPath = "test/vars/callstacks/"
        binding.setProperty('steps', 'some')
        binding.setVariable('env', [getEnvironment: {[:]}])
    }

    @Test
    void publishCdMetricsSuccess() throws Exception {
        cicd = loadScript('vars/cicd.groovy')
        cicd.publishCdMetrics(serviceVersion, team, service, deployEnv, deployType, deployReason)
        printCallStack()
    }
}

/vars/cicd.groovy

import spg.dora.cd.DeploymentMetrics
def publishCdMetrics(serviceVersion, String team, String service, String deployEnv, String deployType, String deployReason) {
    try {
        String[] deployRegions = ['us-west-2'] as String[]
        DeploymentMetrics metricsHandler = new DeploymentMetrics(steps, env, docker)
        metricsHandler.postMetric(team, service, serviceVersion, deployEnv, deployType, deployReason, deployRegions)
    } catch (Exception exception) {
        error "Failed to publish CD metrics: ${exception}"
    }
}

DeploymentMetrics.groovy

class DeploymentMetrics implements Serializable {
    DeploymentMetrics(steps, env, docker) {
        this.steps = steps
        this.env = env
        this.common_shell = new CommonShell(steps, env)
    }

    def postMetric(String team, String service, String serviceVersion, String environment, String category, String reason, String[] awsRegions) {
      ...
      //doesn't return anything
    }
}

我在this 示例之后尝试了new MockFor()

def mockDeploymentMetrics = new MockFor(DeploymentMetrics, true)
mockDeploymentMetrics.demand.with {
     DeploymentMetrics(any(), any(), any()) {
         new DeploymentMetrics(null, null, null)
     }
     postMetric { }
}
mockDeploymentMetrics.use {
     cicd = loadScript('vars/cicd.groovy')
     cicd.publishCdMetrics(serviceVersion, team, service, deployEnv, deployType, deployReason)
}

我尝试了MockPowerMock 的不同组合

@PrepareForTest(DeploymentMetrics.class)
class CICDTest extends BaseRegressionTest {
    @Override
    @Before
    void setUp() throws Exception {
       super.setUp()
       //deploymentMetrics = mock(DeploymentMetrics.class)
       deploymentMetrics = PowerMockito.mock(DeploymentMetrics.class)
       when(deploymentMetrics.postMetric(any(), any(), any(), any(), any(),any(), any())).thenReturn(new Object())
   }
}

我试过metaClass.constructor

DeploymentMetrics.metaClass.constructor = { steps, env, docker ->
   def constructor = DeploymentMetrics.class.getConstructor(Object.class,Object.class,Object.class)
   def instance = constructor.newInstance(any(), any(), any())

我尝试在 this 示例之后实例化类并监视该对象:

DeploymentMetrics deploymentMetrics = new DeploymentMetrics(binding.getVariable("steps"), binding.getVariable("env"), binding.getVariable("docker"))
deploymentMetricsSpy = spy(deploymentMetrics)
doReturn(new Object()).when(deploymentMetricsMock).postMetric(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), any())

但它总是在真正的类和它的方法中。我实际上不希望它进入真正的构造函数,因为它调用其他类的构造函数并且它失败了。所以我想完全避免做新的。

注意DeploymentMetrics 仅有 1 个构造函数,带有 3 个 Object 参数

我遵循了很多例子,但没有任何效果。

有人能解释一下吗?

【问题讨论】:

    标签: java unit-testing groovy junit mocking


    【解决方案1】:

    关于 PowerMock 版本:要模拟构造函数,您应该 PrepareForTests 调用构造函数的类,而不是正在构造的类。您还需要使用 PowerMockRunner。尝试改变:

    @PrepareForTest(DeploymentMetrics.class)
    class CICDTest extends BaseRegressionTest {
    ...
    }
    

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(cicd.class)
    class CICDTest extends BaseRegressionTest {
    
        @Override
        @Before
        void setUp() throws Exception {
           deploymentMetrics = mock(DeploymentMetrics.class)
           PowerMockito.whenNew(DeploymentMetrics.class).withAnyArguments().thenReturn(deploymentMetrics)
           when(deploymentMetrics.postMetric(any(), any(), any(), any(), any(),any(), any())).thenReturn(new Object())
       }
    }
    

    【讨论】:

    • 它不喜欢@PrepareForTest(cicd.class) 也许是因为它在/vars 文件夹中?无论如何,PowerMockito.mock(DeploymentMetrics.class) 确实给了我一个模拟,我在调试时可以看到它,但它仍然调用真正的类。
    • 实际上你还需要模拟构造函数,使用PowerMockito.whenNew,我更新了我的答案。关于@PrepareForTest(cicd.class):没有它就行不通。尝试检查 cicd.groovy 编译到的类的实际名称。
    【解决方案2】:

    @mafor hm...我不确定如何访问 vars 文件夹中的文件:/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-12
      • 1970-01-01
      • 2019-08-29
      • 2016-04-18
      • 2020-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多