3

In my business logic I don't have any scenario for exception, Not sure how to test the catch block in sprint boot Service class. Most of the scenarios are handled in controller level.

But for sonar coverage I need to cover catch block too in my services.

My sample code be like

public void employeeDetails(Object Employee) throws CustomException {
        try {
            int count = commonUtils.calculateEmployeeCount(Employee)
        } catch (Exception e) {
            throw new CustomException(" Exception occurred", e);
        }
    } 

Whether my business logic should have any failure scenarios to test or we have any option to mock custom virtual exception for testing purpose. Any one please advice on this.

Reference

How do you assert that a certain exception is thrown in JUnit 4 tests?

How to Junit test a try catch block in my code

Debugger
  • 690
  • 1
  • 18
  • 41
  • 2
    create a mock that causes `calculateEmployeeCount` to throw and then assert that a proper exception has been thrown, where exactly are you struggling? – luk2302 Feb 17 '21 at 15:15
  • add calculateEmployeeCount code and fill Emplyoyee to throw the exception, an then use Assertions.assertThrows() – Karim Feb 17 '21 at 15:23
  • as @Karim said you should trigger with the Employee object somehow this scenario. If you cannot do that I am wondering why you have this catch block? – PavlMits Feb 17 '21 at 16:22

1 Answers1

5

I assume a class EmployeeServiceImpl implementing EmployeeService with the method void EmployeeDetails(Object Employee). Note, according to the code conventions, the names of methods start with lower-case, so I will follow such convention in my answer.

public void employeeDetails(Object employee) throws CustomException {
    try {
        int count = calculateEmployeeCount(employee)
    } catch (Exception e) {
        throw new CustomException("Exception occurred", e);
    }
} 

You need to achieve calculateEmployeeCount method to throw an exception, which can be any subtype of Exception. For that you need instance of the class having such method. The instance should be either mocked using @MockBean or if it's our EmployeeServiceImpl, you use @SpyBean for partial mocking instead of @Autowired for a production bean with injected beans with precedence of the test ones (@MockBean) over the production ones.

Assuming you use Spring tests starter with Mockito and the same class having calculateEmployeeCount method (judging from its name).

@SpyBean
private EmployeeService employeeService;
Mockito.when(employeeService.calculateEmployeeCount())
       .thenThrow(new Exception("An exception"));

The final step is a verification of whether the CustomException was thrown:

Object employee = new Object();                        // it doesn't need to be a mock

CustomException exception = Assertions.assertThrows(
     CustomException.class,
     () -> employeeService.employeeDetails(employee));

// the thrown exception is available fur further testing (of the message, cause etc.)
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • Thanks Nikolas, Based on your suggestion I'm able to check custom exceptions. But SpyBean and our test cases are not reflected in jacco codecoverage report. Still report showing catch blocks are not covered. Any suggestions ? – Debugger Feb 18 '21 at 05:44
  • calculateEmployeeCount method is from another class. I just updated the same – Debugger Feb 18 '21 at 08:30
  • 1
    In that case use `@Autowired` with `@MockBean` combo. All that `@SpyBean` does is it creates a wrapper around the real implementation deciding whether its original or mock methods are called. It's strange the `catch` clause doesn't appear covered in SonarQube, however, it is in fact covered. Lastly, don't aim for 100% coverage. Instead of covering **all* code, focus on the *important* one. – Nikolas Charalambidis Feb 18 '21 at 22:30