0

As a precondition for my tests I need to set up a big complex object model, which later will be posted as an argument to specific API in order to process it.

Values for the model are test input data which is displayed on the FitNesse page.

The model looks like:

class FinalEntity extends DoFixture{
    public String field1;
    public String field2;
    // More fields....
    public String field20;
    public ArgumentOneEntity argOne;
    public List<ArgumentTwoEntity> argTwo;
    // More fields....
    //Getters and setters ....

}

class ArgumentOneEntity{
    public String field1;
    public String field2;
    // More fields....
    public List<String> argList = new ArrayList();
    public List<String> argList1 = new ArrayList();

    //Getters and setters ...
}

class ArgumentTwoEntity{
    public String field1;
    public String field2;
    // More fields....
    //Getters and setters ...
}

It's possible to use a table but it's extremely inconvinient.

With FIT it was possible to do something like this:

!define argOne (|field1|value1|
|field2|value2|
|setArgList;|arg1,arg2,arg3|
|setArgList1;|arg4,arg5,arg6|
)

!define argTwo (|field1|value1|
|field2|value2|
)

|FinalEntity |
|setField1;|${argOne}|
|setField2;|${argTwo}|

It would parse in some magical way tables from variable to a required question. Now the question is: How to make it work with SLIM?

If that's not possible, what are reasonable alternatives to building such an object in SLIM without making a huge messy table, which no one understands?

Options I thought about:

  1. To store test data in files in corresponding JSON objects parse them and show to business users in FitNesse pages.

I don't like it, because it's very inconvenient to maintain such tests - you need to run the test or to search for corresponding file with data.

  1. To add both dependencies for SLIM and FIT in order to benefit both from SLIM and FIT library.

That didn't work - Fitnesse server would simply not start.

  1. Used table - that was very painful and hard to maintain.

Do you have any reasonable solutions to this problem?

No need to say things like updating your model - I cannot do that, or use something else like JBehave - I would love to do so, moreover I had a positive experience with JBehave in the past, but regretfully, in this case, I'm not the one who makes the decision about technologies and approaches.

n-verbitsky
  • 552
  • 2
  • 9
  • 20
  • Do you have to fill the Java objects, or do you just have to get a proper request to the API? You indicate you must post, are you talking about a http post of json, XML or something else? – Fried Hoeben Aug 12 '16 at 19:40
  • Java object is passed then as a model argument to the API. As a possibility I'm thinking about wrapping variables to JSON or XML and then pass it as string to Java and there I may use Jackson or JAXB to parse it, but it looks pretty weird - too many conversion actions. Therefore I thought maybe there's some straightforward solution I don't know about, since I'm not an expert in Fitnesse. – Alex Bugtracker Aug 13 '16 at 23:18

1 Answers1

0

I recommend focussing on the call to the API, instead of filling a POJO structure which is not really what you want to test. A POST is nothing more than sending a string in a http call, so to write a test you need to setup the correct string to send to the API.

You can do that by creating/generating a Java client and then from the wiki fill its (complex) model to make the call, as you question suggests. Another approach (which I recommend, and have created generic fixtures to support) is to create a template of the body to post and use the wiki to fill placeholders in that template. Then no (API) specific Java code is needed, in other words there will be no POJO to fill.

The template can either be completely in the wiki, using a Slim scenario (if there is a fixed set of placeholders to be filled) or in a separate file which is filled using a templating engine (if more flexibility is needed such as optional placeholders or lists of variable length). In the latter case the data structure to provide the placeholders to the templating engine is just a hash/map with keys and values (instead of a pojo with getters and setters). In the former case the placeholders are provided as parameters to the scenario.

Scenario Based

Using a scenario to generate two request, with placeholder for zip code:

!*> Scenario definition
!define POST_BODY_2 { {{{
<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
  <s11:Body>
    <ns1:GetCityWeatherByZIP xmlns:ns1="http://ws.cdyne.com/WeatherWS/">
      <ns1:ZIP>@{zip}</ns1:ZIP>
    </ns1:GetCityWeatherByZIP>
  </s11:Body>
</s11:Envelope>
}}} }

|script|xml http test|

|scenario |send request _|zip, City                                                       |
|post           |${POST_BODY_2} |to                   |${URL}                        |
|check          |response status|200                                                 |
|show           |response                                                            |
|register prefix|weather        |for namespace        |http://ws.cdyne.com/WeatherWS/|
|check          |xPath          |//weather:City/text()|@{City}                       |
*!

|send request       |
|zip  |City         |
|10007|New York     |
|94102|San Francisco|

Test output with scenario

Freemarker Template

By using a Freemarker template we can have more dynamic body content (and the placeholders are filled using 'set value for ' method). With this template (samplePost.ftl.xml):

<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
    <s11:Body>
        <ns1:GetWeather xmlns:ns1="http://www.webserviceX.NET">
            <#if cityName??>
            <ns1:CityName>${cityName}</ns1:CityName>
            </#if>
            <ns1:CountryName>${countryName}</ns1:CountryName>
        </ns1:GetWeather>
    </s11:Body>
</s11:Envelope>

The following wiki can be created:

!define GLOBAL_WEATHER_URL {http://www.webservicex.com/globalweather.asmx}
!define GLOBAL_WEATHER_TEMPLATE_NAME {samplePost.ftl.xml}

!3 Don't send a cityName element: error

The Freemarker template will not send a cityName element if no value is supplied (the whole element will be omitted, as can be seen in the request below). The service will not like this.
Omitting the element on a null value could not be done when the body was in the scenario content.

|script          |xml http test                                               |
|template        |${GLOBAL_WEATHER_TEMPLATE_NAME}                             |
|set value       |http://www.webserviceX.NET/GetWeather|for header|SOAPAction |
|set value       |Canada                               |for       |countryName|
|post template to|${GLOBAL_WEATHER_URL}                                       |
|check           |response status                      |500                   |
|show            |request                                                     |
|show            |response                                                    |

!3 Send a cityName element: success

When a cityName value is set the enclosing element is sent by the Freemarker template (as visible in the shown request content below), and the SOAP call will succeed.

|script          |xml http test                                                                   |
|template        |${GLOBAL_WEATHER_TEMPLATE_NAME}                                                 |
|set value       |http://www.webserviceX.NET/GetWeather  |for header   |SOAPAction                |
|set value       |Canada                                 |for          |countryName               |
|set value       |Vancouver International Air-Port, B. C.|for          |cityName                  |
|post template to|${GLOBAL_WEATHER_URL}                                                           |
|check           |response status                        |200                                     |
|show            |request                                                                         |
|show            |response                                                                        |
|register prefix |wsX                                    |for namespace|http://www.webserviceX.NET|
|show            |xPath                                  |!-//wsX:GetWeatherResult/text()-!       |

Freemarker based test output

These two examples post XML but the same approach can, of course, also be used for JSON APIs (I then suggest to use the 'json http test' fixture, which supports json path instead of xPath for make assertions on the response received).

When more complex placeholders are needed (e.g. lists of variable length) or you would like to group your placeholders into multiple nested hashes (as you would do with nested objects in a POJO model) this can also be achieved by using a more elaborate key name (e.g. |set value|someone@example.com|for|email.to[1]|)

The fixtures used above can either be downloaded from GitHub, or via Maven using:

<dependency>
    <groupId>nl.hsac</groupId>
    <artifactId>hsac-fitnesse-fixtures</artifactId>
    <version>2.7.1</version>
</dependency>

You can try whether this approach works for you API by just downloading the 'standalone zip' version of the project, unzip it, run it and then updating one of the example wiki pages to post to URL of your API with an updated template and execute the page/test.

Fried Hoeben
  • 3,247
  • 16
  • 14