2
1
0

I need to add a SvcConn to an existing SvcDef parameter in my unit test. How do I create and add a configured SvcConn object to an existing SvcDef object using the Fluent API?

Thanks,

Blake

    CommentAdd your comment...

    3 answers

    1.  
      2
      1
      0

      Thanks Ben Warner for the tip. For anyone else that comes across this, there is an Ant Task in the Transact SDK called app-scaffold-connect. This task will create a test connection for you in your project. You can then modify its json definition file to set the user name, password & endpoint, making these available for your unit tests.

      1. Ben Warner

        Thanks Sean, I've alerted our knowledge team to this gap in the documentation.

      2. Sean Colyer

        Ben Warner - I've just tried running this through the svc-test Ant build task and it appears that the endpoint, username and password are not being propagated through to the test svcDef.scvConn. Interestingly, everything works fine when I run it through the IntelliJ unit test runner.

        Any ideas on what is going on here?

      3. Sean Colyer

        For reference, here's a stack trace:

        <testcase classname="com.avoka.tm.test.JUnitTestRunner$TestWrapper" name="testSuccessfulGetMemberCall" time="0.014">
            <error message="Null username parameter" type="java.lang.IllegalArgumentException">java.lang.IllegalArgumentException: Null username parameter
        	at com.avoka.tm.util.Contract.notBlank(Contract.java:50)
        	at com.avoka.tm.http.HttpRequest.setNtlmAuth(HttpRequest.java:155)
        	at com.cusa.integration.dataaction.DACallAPITest.testSuccessfulGetMemberCall(DACallAPITest.groovy:37)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at com.avoka.tm.test.JUnitTestRunner.run(JUnitTestRunner.java:84)
        	at com.avoka.tm.test.JUnitTestRunner.runTests(JUnitTestRunner.java:47)
        	at com.avoka.tm.test.AbstractJUnitTest.invoke(AbstractJUnitTest.java:120)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at com.avoka.core.groovy.runtime.SecureStaticGroovyTask.call(SecureStaticGroovyTask.java:177)
        	at com.avoka.core.groovy.runtime.GroovyScriptRuntime.executeScript(GroovyScriptRuntime.java:266)
        	at com.avoka.core.groovy.runtime.GroovyScriptRuntime.executeScript(GroovyScriptRuntime.java:99)
        	at com.avoka.fc.core.service.fluent.AbstractFluentService.runUnitTest(AbstractFluentService.java:260)
        	at com.avoka.transact.ant.svc.SvcTest.execute(SvcTest.java:118)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at com.intellij.rt.ant.execution.AntMain2.main(AntMain2.java:30)
        </error>
          </testcase>

        I've tried changing the svc-package to include the contents of the connections directory in the target directory but this still doesn't work.

      CommentAdd your comment...
    2.  
      2
      1
      0

      More context on what you are trying to achieve would be helpful. Do you just need to use different connection parameters in your unit test?

      In this case I would look at adding test parameters to the service containing the test endpoint information.

      You should then be able to update the Service Connection i your test script as follows:

      new SvcConnUpdater(svcDef.svcConn).setEndpoint(testParams.get("testEndpoint").update()
      1. Blake Hunter

        I think the real problem here is that I cannot create a new SvcDef or SvcConn object with the Fluent API. My unit test #invoke method provides me with a SvcDef that is created without a SvcConn and I cannot create a new SvcConn to provide to the SvcConnUpdater that you described above. I think for developers to be able to setup the proper object configuration to create different test case scenarios then we need support from the fluent API to be able to create both SvcDef and SvcConn objects. I simply cannot write my unit test at the moment to test different scenarios.

      2. Ben Warner

        Can you clearly explain your use case as I'm having a lot of trouble trying to understand why you would want to create a new SvcDef in a unit test. The idea of a unit test script is to test an existing SvcDef.

        I also don't understand why you would want to create a new SvcConn and apply it to a SvcDef that does not already have an SvcConn defined. If your SvcDef is created without a SvcConn then simply add the serviceConnection attribute to your service-def.json file as described here and my suggestion above should work for you.

      3. Blake Hunter

        My service under test will take a SvcDef as an input parameter. It will then call a method that takes the SvcDef and gets the SvcConn from that and then gets the Banamex service endpoint from that SvcConn. It does this to generate the full URL that I will need to call an external Banamex Service. 

        This is what the code looks like: 

        String provideUrl(SvcDef serviceDefinition, String servicePath) {
            Contract.notNull(serviceDefinition, "serviceDefinition")
            Contract.notBlank(serviceDefinition.svcConn.endpoint, "serviceDefinition.svcConn.endpoint")
            Contract.notBlank(servicePath, "servicePath")
            URI uri = new URIBuilder(serviceDefinition.svcConn.endpoint)
                    .setPath(servicePath)
                    .build()
            return uri.toString()
        }

        If I don't provide my service under test with a service definition (SvcDef) that contains the SvcConn with my endpoint then it will throw an NPE. I need this to make sure that my service is actually working and calling my endpoint. 

        I'm also sure that at some point I will want to create alternate SvcDef and SvcConn objects for other test cases with different configurations to simulate different real world scenarios. 

      4. Ben Warner

        If you need to create additional service definitions then use the Fluent SDK for this, don't try to do it in unit test code. The function above could take a SvcConn object instead of a SvcDef object and still function the same way.

        I can see an edge case for creating new SvcConn objects in test scripts so you may want to request this feature.

      5. Blake Hunter

        The invoke method in my fluent service does not take a SvcConn object so I have no way of passing that object into my service under test. Additionally I should not be making changes to my production code for the sole purpose of supporting a unit test.

        I can only interact with my service under test through objects passed into the #invoke parameters or querying the DB to retrieve persistent entities. We need to have the flexibility to build any an all configurations of any parameter we pass to the fluent service invoke methods so we can drive the different execution paths needed for test cases.

      6. Sean Colyer

        Ben Warner I'm trying to do a similar thing - write a unit test for a service that makes an API call to one of our other vendor's systems, and utilise the username, password, & endpoint specified on svcDef.svcConn.

        When the unit test is initialised it contains a svcDef variable but svcDef.svcConn is null.

        I've tried configuring the service-def.json as described but this does not instantiate svcConn when running via the IntelliJ Unit Test runner.

        Here's our service-def.json (I've changed the name of the vendor):

        {
          "name": "Vendor - Call API",
          "description": "TODO...",
          "type": "Groovy Service",
          "version": "0.1.0",
          "tmMinVersion": "5.0.0",
          "legacyGroovy": false,
          "serviceConnection": "Vendor Name",
          "parameters": [
            {
              "name": "groovyScript",
              "filePath": "VendorCallAPI.groovy",
              "fileIncludes": [],
              "bind": true,
              "required": false,
              "clearOnExport": false,
              "readOnly": false
            },
            {
              "name": "ReadTimeout",
              "value": "600000",
              "bind": true,
              "required": true,
              "clearOnExport": false,
              "readOnly": true,
              "type": "String"
            },
            {
              "name": "ConnectTimeOut",
              "value": "600000",
              "bind": true,
              "required": true,
              "clearOnExport": false,
              "readOnly": true,
              "type": "String"
            },
            {
              "name": "Unit Test Script",
              "filePath": "VendorCallAPITest.groovy",
              "fileIncludes": [],
              "bind": false,
              "required": false,
              "clearOnExport": false,
              "readOnly": false,
              "unitTest": true
            },
            {
              "name": "Test XML",
              "type": "String",
              "filePath": "test-soap-envelope.xml",
              "bind": false,
              "required": false,
              "clearOnExport": false,
              "readOnly": false,
              "unitTest": true
            },
            {
              "name": "Mock Response",
              "type": "String",
              "filePath": "vendor-api-response-body.xml",
              "bind": false,
              "required": false,
              "clearOnExport": false,
              "readOnly": false,
              "unitTest": true
            },
            {
              "name": "Help Doc",
              "type": "HTML",
              "filePath": "service-help.html",
              "bind": false,
              "required": false,
              "clearOnExport": false,
              "readOnly": false
            }
          ]
        }
      7. Sean Colyer

        Any clues on how to get this object to not be null would be appreciated!

      8. Ben Warner

        Hey Sean, I'm assuming you are using the 17.10 SDK. Have you reviewed the SDK documentation? You can create a local SvcConn object in an application package using the app-scaffold-connect ant target.

        https://support.avoka.com/kb/display/TSDK/Transact+SDK+Documentation


         

      9. Sean Colyer

        Hi Ben, yes we are using 17.10. I had reviewed the documentation, but there isn't an entry for app-scaffold-connect so I had no idea what it did. I'll try to muddle my way through now but if there is a section somewhere other than the Ant-Tasks page in the SDK docs can you please point me to it?

      CommentAdd your comment...
    3.  
      1
      0
      -1

      Hi Blake,

      The short answer is that you cannot do that to an existing SvcDef object.

      SvcDef declares its svcConn member as final, so it cannot be set outside the constructor.

      You can create a new SvcDef object using the constructor which takes a ServiceDefinition as parameter.  That would populate the svcConn member with a new SvcConn object.

      Can you provide a little more information about what you are trying to achieve?

      1. Blake Hunter

        Hi Bill,

        I did attempt to create a new SvcDef object using its constructor with a ServiceDefinition as an argument but I cannot create or even import the ServiceDefinition class into a fluent class as it is part of the restricted core API. So I'm a bit stuck at the moment.

        I am trying to configure the SvcDef to be used by my service to include the SvcConn that I will define with a custom defined endpoint.

        Thanks,

        Blake

      CommentAdd your comment...