Integration Testing

In the last section, we talked about unit testing, where we tested each individual unit independently and recommended mocking any external services. With integration testing, our focus is the reverse, that is, we actually want to test whether our service is able to communicate with any outside resources or services. If the other service is down or not reachable, will our service handle the scenario gracefully?

So, revisiting our example, where we talked about fetching a constant value from a third-party service, we have the following:

FetchConstantService fetchConstantService = new FetchConstantService();
CalculatorController(FetchConstantService fetchConstantService)
{
this.fetchConstantService = fetchConstantService;
}

/**Request to divide 2 numbers*/
* @api {get} /dividebyconstant?num1={num1}&num2={num2}
* @apiName Divide
* @apiGroup Calculate
* @apiVersion 1.0.0
** @apiParam {Number} num1 first number
** @apiSuccess {Number}
@GetMapping("/dividebyconstant")
public float divideNumberByConstant(float num1)
{
float num2 = fetchConstant();
return(float)(num1/num2);
}
/**** This method return a constant value based on a third party service
* @return*/
public float fetchConstant()
{
return fetchConstantService.getConstantValue();
}

We are using a service that is a black box to us. We do not know what is happening behind the scenes; it might be fetching the data from some file, some database, some third-party service, or so on. This black box can fail or behave in an unanticipated manner. That is what integration testing is all about! We will not mock fetchConstant this time, and see what will happen in the following code:

/*** This method tests divide by constant- no mocks*/
@Test
public void divideByConstantSuccessNoMockTest()
{
FetchConstantService fetchConstantService = new FetchConstantService();
CalculatorController calculatorController = new CalculatorController(fetchConstantService);
int num1 = 10;
// define return value for method
getUniqueId()
float expectedResult = 2;
float actualResult = calculatorController.divideNumberByConstant(num1);
assertEquals(expectedResult, actualResult, 0);
}

This test case actually brings out a lot of flaws in our code. For example, we have not handled the cases where the black box service is not responding or taking a lot of time. When we start integration testing, we will be forced to harden our service, to make sure we handle all the corner cases. 

The following code shows an example of an integration test:

@GetMapping("/dividebyconstant")
public float divideNumberByConstant(float num1)
{
float num2;
try
{
num2 = fetchConstant();
}
catch(Exception e)
{
// In real code we will handle multiple exceptions expected
// and not just the high level exception
// Once an error occur, we will need to handle it.
// We will need to log the proper error and handle it gracefully
// so that or code does not break.
num2 = 2;
}
return(float)(num1/num2);
}

We also  need to add timeouts to make sure our services do not get stuck for long periods of time. These best practices help our code to be robust and disaster-ready. A good integration test brings out loopholes in your code and fixes the problems before end users start reporting them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.173.238