当前位置: 首页 > 知识库问答 >
问题:

在Spock框架中运行测试时,无法模拟类中的属性值

鲁涵意
2023-03-14

在运行spock测试时,我需要帮助模拟一个类及其从yaml文件获得的数据。我有一个用groovy编写的microservice,它根据yaml文件中的字段名参数进行字段映射。

我有一个projectProperties类,它从yaml文件中提取数据。

import org.springframework.stereotype.Component
import groovy.json.JsonBuilder
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties

@Component
@ConfigurationProperties(prefix = "config")
@EnableConfigurationProperties
public class ProjectProperties {
    List<String> inputFields = new ArrayList<String>();
    String outputField;
    String mapname;
}

这个类将从 /src/main/resourcesapplication.yaml文件中提取变量值

config:
    inputFields:
        - 'Custom.WorkaroundComplexity'
        - 'Custom.Frequency'
    outputField: 'Custom.Impact'
    mapname: 'impactMap.json'

当我运行spock测试时,它无法从project ectProperties类和yaml文件中拉入变量。输入值处理为NULL

下面是在MapFieldMicroService类中引入project ectProperties参数数据的代码部分

@Component
@Slf4j
class MapFieldMicroService implements MessageReceiverTrait {

// Remark by kriegaex: Here there seems to be a method declaration missing.
// The code is directly inside the class, which does not make any sense.

        if (projectProperties.inputFields.size() != 2) {
            log.error("Must have two input field values")
            return 'Invalid parameters'
        }
        
        //Get field attributes from YAML file
        String geninput1 =  projectProperties.inputFields[0]
        String geninput2 = projectProperties.inputFields[1]
        String genoutput = projectProperties.outputField
        String input1value = "${wiResource.revision.fields[geninput1]}"
        String input2value = "${wiResource.revision.fields[geninput2]}"
        String newOutput

当我运行spock测试时,它会在上面的if语句上停止,因为它无法拉入project ectProperties值。

它在“必须有两个输入字段值”时停止,当然,从这个类/yaml文件中提取数据的变量在调试中是空的。

String geninput1 =  projectProperties.inputFields[0]
String geninput2 = projectProperties.inputFields[1]
String genoutput = projectProperties.outputField

我猜我需要在测试中模拟这些属性,以避免遇到这个问题。这是我的测试课。它引入了一个json文件,其中包含运行测试所需的事件数据,并避免了连接到系统。microservice是一种映射服务,它根据添加到两个输入字段的数据计算输出。该测试还具有@Autowired主类MapFieldMicroService和ProjectProperties文件以及@Beans。

import static org.junit.Assert.*

import com.bcg.common.services.rest.IGenericRestClient
import com.bcg.common.services.test.SpockLabeler
import com.bcg.vsts.services.mapfield.ProjectPropertiesTest
import com.bcg.vsts.services.asset.SharedAssetService
import com.bcg.vsts.services.mapfield.MapFieldMicroService
import com.bcg.vsts.services.tfs.rest.GenericRestClient
import com.bcg.vsts.services.work.WorkManagementService
import groovyx.net.http.ContentType
import org.junit.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Profile
import org.springframework.context.annotation.PropertySource
import org.springframework.test.context.ContextConfiguration
import groovy.json.JsonSlurper
import spock.lang.Ignore
import spock.lang.Specification
import spock.mock.DetachedMockFactory

@ContextConfiguration(classes=[MapFieldMicroserviceTestConfig])
class MapFieldMicroServiceSpec extends Specification {
  @Autowired
  MapFieldMicroService underTest;

  @Autowired
  WorkManagementService workManagementService;

  @Autowired
  ProjectProperties projectProperties

  def "Complexity and Frequency are set, but output is unassigned"() {

    given: "A mock ADO event payload where Assigned To is already set"

    def adoEvent = new JsonSlurper().parseText(this.getClass().getResource('/testdata/adoDataMissingOutput.json').text)

    and: "stub input1 and input2 values for testing"
    def list1 = ['Custom.WorkaroundComplexity', 'Custom.Frequency']
    String outputTest = 'Custom.Impact'

    projectProperties.inputFields >>  new ArrayList<String>(list1)
    projectProperties.outputField >>  outputTest

    and: "stub workManagementService.updateItem()"
    workManagementService.updateWorkItem(_,_,_,_) >> { args ->
      String data = "${args[3]}"
      // Inject mapped outs here to test full output map
      assert(data.toString() == "[[op:test, path:/rev, value:127], [op:add, path:/fields/$outputTest, value:$Output]]")
    }

    when: "ADO sends notification with set Complexity and Frequency"
    adoEvent.resource.revision.fields.'Custom.WorkaroundComplexity' = Input1
    adoEvent.resource.revision.fields.'Custom.Frequency' = Input2
    def resp = underTest.processADOData(adoEvent)

    then: "Output is updated to the expected value"
    //resp == "Output value updated"
    resp == "Output value updated to: $Output"

    where:
    Input1   | Input2       | Output
    "Low"    | "Infrequent" | "Low"
    "Low"    | "Monthly"    | "Low"
    "Low"    | "Daily"      | "Medium"
    "Medium" | "Monthly"    | "Medium"
    "Medium" | "Infrequent" | "Medium"
    "Medium" | "Daily"      | "High"
    "High"   | "Infrequent" | "Medium"
    "High"   | "Daily"      | "High"
    "High"   | "Monthly"    | "Medium"
  }
}
@PropertySource("classpath:test.yaml")
class MapFieldMicroserviceTestConfig {
    def mockFactory = new DetachedMockFactory()
    
    @Bean
    ProjectProperties projectProperties() {
        return new ProjectProperties()
    }
    
    @Bean
    MapFieldMicroService underTest() {
        return new MapFieldMicroService()
    }
}

我知道这涉及到很多代码和文件,但任何关于如何模拟此属性数据的帮助都将不胜感激。

共有1个答案

秦涵映
2023-03-14

谢谢大家在这方面的帮助。我可以通过添加mockFactory来模拟属性文件输入。此代码块的存根-

    @Bean
ProjectProperties projectProperties() {
    return new ProjectProperties()
}

如在:

    @Bean
ProjectProperties projectProperties() {
    return mockFactory.Stub(ProjectProperties)
 类似资料:
  • 我很难在Java项目中使用Spock框架进行测试。我有以下内容: 但是,对于我的具体情况,我需要指定我传入的Person对象,并为其分配一个特定的MockReturnObject。比如: 或 这两种方法都不起作用,调用最终返回null而不是MockReturnObjectA(我认为这是因为它无法匹配参数)。不幸的是,我对Spock没有太多的经验,我试图搜索关于在这种情况下处理地图的文档,但没有取得

  • 我在StackOverflow和Google上搜索了一段时间,试图找到能够在Spock规范中运行此代码的正确配置/语法: 然而,当我运行单元测试时,cglib向我抛出了一个令人讨厌的异常: 我看了这个问题/答案--用Stock中的GroovyMock或类似的方法模拟静态方法--希望它能给我一个好的起点,但是在我的例子中被模拟的类groovy.sql是一个groovy类,所以我不确定它是正确的起点。

  • 我用编写了以下测试(使用框架时): 然而,当我运行它时,字段似乎丢失了。我得到以下错误: 我想知道为什么,因为我在一节中声明了它。你能帮我吗?

  • 问题内容: 我有一个定义类属性的基类和一些依赖它的子类,例如 我想用不同的 分配 对这个类进行单元测试,例如空字典,单个项目等。当然这是极其简化的,这与重构我的类或测试无关 我提出的(pytest)测试最终是 这感觉很复杂而且很笨拙-我什至还不完全了解它为什么起作用(尽管我对描述符很熟悉)。模拟会自动将类属性转换为描述符吗? 感觉更合乎逻辑的解决方案不起作用: 要不就 我尝试过的其他变体也不起作用

  • 我正在使用Spring boot和Mockito进行测试。我已经能够为服务层编写测试用例,它们工作得很好。但是,针对DAO层的测试用例却没有。在执行测试用例时,被mocked和autowired的对象提供指针。以下是详细情况: 我的类: java:

  • Spock对存根和模拟做了很强的区分。当要更改的内容从被测试类使用的类返回时,请使用存根,这样您就可以测试if语句的另一个分支。使用mock,当您不关心测试中的类返回什么时,只需调用另一个类的另一个方法,并且您希望确保调用了该方法。很整洁。然而,假设您有一个具有流利API的构建器,它使人们。您希望测试调用此生成器的方法。 所以最初,我想只是模拟构建器,然后myMethod()的单元测试应该检查具有