1

I need help mocking a class and the data it get's from a yaml file when running a spock test I have a microservice written in groovy that does field mapping based on field name parameters in a yaml file.

I have a projectProperties class that pulls in the data from that yaml file.

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;
}

This class will pull in the variable values from the application.yaml file from /src/main/resources

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

When I run my spock test it's unable to pull in the variables from the projectProperties class and yaml file. The input values process as NULL

Here's the section of code that pulls in the projectProperties paramter data in MapFieldMicroService class

@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

When I run the spock test it stops on the If statement above because it can’t pull in the projectProperties values.

It stops on “Must have two input field values” and of course the variables pull data from this class/yaml file are coming as null in debug.

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

I’m guessing I need to do something to mock these properties in my test to avoid running into this problem. Here’s my test class. It’s pulling in a json file that contains event data needed to run the test and avoid having to connect to the system. The microservice is mapping service that calculates an output based on data added to two input fields. The test also has @Autowired the main class MapFieldMicroService and the ProjectProperties file as well as @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()
    }
}

I know this a lot of code and files involved but any help would be appreciated on how to mock this properties data.

2
  • @PropertySource doesn't support yaml out of the box, try baeldung.com/spring-yaml-propertysource Commented Feb 11, 2021 at 0:30
  • In class MapFieldMicroService there is a method declaration missing. I added a comment in your code. I also added syntax highlighting, fixed the Spock spec's formatting and split the code blocks to one per class. Please give yor own questions some more love in the future. Thank you. Commented Feb 11, 2021 at 6:16

1 Answer 1

1

Thanks for everyone's help with this. I was able to mock the property file inputs by adding mockFactory.Stub to this block of code -

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

As in:

    @Bean
ProjectProperties projectProperties() {
    return mockFactory.Stub(ProjectProperties)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.