Unit testing

The idea is to test each unit of your application independently. This is mostly easy to implement, as we are focusing on only one unit at a time. For each unit, we need to think about all the cases that can occur. For example, let's take the simple division method from our previous example, as follows:

public float divideNumber(float num1, float num2) 
{
return(float)(num1/num2);
}

We will need to think whether the divide by zero error is handled. Can I divide negative numbers? Are fractions being handled? For a simple single-line method, we can think of so many scenarios. So, let's take a look at what our Unit-testing class would look like:

package com.packt.Microservices.calculator2;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Calculator2ApplicationTests
{
/*** This method tests division of 2 integers*/
@Test
public void divideIntegerSuccessTest()
{
CalculatorController calculatorController = new CalculatorController();
int num1 = 10;
int num2 = 5;
float expectedResult = 2;
float actualResult = calculatorController.divideNumber(num1, num2);
assertEquals(expectedResult, actualResult, 0);
}
/*** This method tests for division of two float numbers*/
@Test
public void divideFloatSuccessTest()
{
float num1 = (float) 55.5;
float num2 = (float) 11.1;
float expectedResult = 5;
float actualResult = calculatorController.divideNumber(num1, num2);
assertEquals(expectedResult, actualResult, 0);
}
/*** This method tests for division by negative numbers*/
@Test
public void divideFloatNegativeSuccessTest()
{
CalculatorController calculatorController = new CalculatorController();
float num1 = (float) -55.5;
float num2 = (float) -11.1;
float expectedResult = 5;
float actualResult = calculatorController.divideNumber(num1, num2);
assertEquals(expectedResult, actualResult, 0);
}
/*** This method tests for division by negative numbers*/
@Test
public void divideByZeroTest()
{
CalculatorController calculatorController = new CalculatorController();
int num1 = 30;
int num2 = 0;
float expectedResult = Float.POSITIVE_INFINITY;
float actualResult = calculatorController.divideNumber(num1, num2);
assertEquals(expectedResult, actualResult, 0);
}
}

We have written so many test cases for a single line of code. One important question that comes up time and time again is, "How much unit testing is sufficient?" One way to track that is through code coverage. We should normally target for 90% code coverage. But this number can go up or down based on your application. For example, in our case, we have only a single line of code, so we will definitely achieve 100% coverage with just a single test case. But it is good to cover just as many corner cases as well, for example, if an error occurs at some point, how the application would behave.

When talking about Unit testing, another important factor is mocking. Let's say your code interacts with additional code, which might be a part of the same service or a different service. We would ideally like to mock any such outsider service, as all we want to test right now is a current unit in hand, that is the unit we want to validate.

To understand the power of mocking, let's extend our previous example a little bit. Let's say we need to divide a number by a constant value, and this value will be supplied by another third-party service. We will use the constructor injection to add the third-party dependency, as follows:

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} Quotient when num1 is divided by constant.
@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();
}

The divideNumberByConstant method is of interest to us. We would like to test how this method would work. But we can clearly see that this method calls another method, and that another method calls a third-party service. Now we do not have any control over the third-party services; moreover, we might not want to test them, as they would be tested by the team providing them. So, why waste time testing something that is already tested! In such cases, it is logical to mock any dependencies that we don't want to test.

There are many libraries to implement mocking. As an example, we will use Mockito, as follows:

/*** This method tests divide by constant*/
@Test
public void divideByConstantSuccessTest()
{
FetchConstantService fetchConstantService = Mockito.mock(FetchConstantService.class);
when(fetchConstantService.getConstantValue()).thenReturn((float) 2);
CalculatorController calculatorController = new CalculatorController(fetchConstantService);
int num1 = 10;
// define return value for method
getUniqueId()
float expectedResult = 5;
float actualResult = calculatorController.divideNumberByConstant(num1);
assertEquals(expectedResult, actualResult, 0);
}

The idea is to assume that, when the third-party service works fine, our code should work well.

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

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