Unit-testing – Spring – rest API – How to unit test a rest API which gets data from another service

mockingspringunit testing

I am new to rest API's as well as mocks. Please help me ..

I have a set of rest API's for which I need to write unit tests. rest API in turn calls another service , gets the JSON response and sends the response [data] back. Basically it's querying a list of master data's like users, suppliers , countries etc etc.

My question is how can I unit test this ?. Any sample code would help me to start ?

)

package mds;
/* all imports removed here */

Please note the below, this url refers to external service which returns the data to my rest API under test

**//external service uri from properties file example value in properties file

// https://svcdev7ows.lab1.com/Arches/search/select?

String archesURL = null;** 

@Value("${mds.arches.address}"

@RestController

@RequestMapping("/api")

public class MasterdataSearchService
{

private static final long serialVersionUID = 1L;
private static final String USER_AGENT = "Mozilla/5.0";
private final String[] excludeFields = { "ir_classname", "arches_type" };
public static final String KeyRealm = "realm";

public static final String MDSAdapterId = "app.masterdataservice";
public static final String irClassName = "ir_classname";
public static final String masterdataClassParameter = "System.Base.MasterdataClassList.Register";

static Hashtable<String, String> pathToClassNameMap = new Hashtable<String, String>();

//external service uri from properties file

@Value("${mds.arches.address}")

String archesURL = null;

@Value("#{${mds.ir_class.path}}")
private Map<String, String> irClassNames;

static String searchOptions = "arches.preview=false&sort=score desc,DefaultRelevance desc&wt=json";
static ClientHttpRequestFactory requestFactory;

@Autowired
private ResourceLoader resourceLoader;

@RequestMapping(value = "data/{classObject}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String getListOfClassObject (@PathVariable("classObject") String classObject,
                                                  @RequestParam(value = "fields",required=false) List<String> fields,
                                                  @RequestParam(value = "uniquename",required=false) String uniqueName,
                                                  @RequestParam(value = "name",required=false) String name,
                                                  @RequestParam(value = "rows",required=false) int rows) throws JSONException, Exception
{

    //hardcoded for better understanding
    String anId = "71000003015" ;  
    String client= "ups" ;      

    searchTerms.add(new SearchTerm("ir_classname", irClassNames.get(classObject)));

    if (!StringUtils.isEmpty(name)) {

        if (classObject.equals("commoditycodes")) {
            searchTerms.add(new SearchTerm("HierarchyPath", name));
        }
        else {
            searchTerms.add(new SearchTerm("Name", name));
        }
    }

    if (!StringUtils.isEmpty(uniqueName)) {
        searchTerms.add(new SearchTerm("UniqueName", uniqueName));
    }

    StringBuilder sb = new StringBuilder();


    sb.append(
        archesURL + searchOptions + "&adapter=" + MDSAdapterId + "&tenant=" + anId + "." + client + "&q=" + "(");

    for (SearchTerm st : searchTerms) {
        sb.append(st.toString());
    }
    sb.append(")");

    if (rows > 0) {
        sb.append("&rows=" + rows);
    }

    // Get only the fields specified by "field" query parameter
    // else get every fields for the object
    sb.append(getReturnFields(fields));

    JSONArray arr = getJSONArrayFromResponse(sendGet(sb.toString()));

    return arr.toString();

}

Best Answer

Standard way is to create a mock of the class/method which calls the external service. This mock verifies that the request (URL) is correct and returns back a response - note that it doesn't call the external service.

You can do this by encapsulating this sendGet() into it's own service class with interface. In test code, you instantiate and inject mock implementation of this interface into the controller class instead of the real implementation one (which is used in production).

If you want an integration test instead of unit test, you can use something like WireMock to create mock server which handles the external service. This is more work, but can detect more problems with your implementation.

Related Topic