- Testing is done using Mockito Junit
- Mocking and Spying using Mockito
- Testing Restful Services with Spring Boot and Mockito.
- Frameworks for Unit Test Cases
- Mockito
- Spring Boot Test Framework
- Layer based Testing Frameworks
- For Web Layer
- Spring Mock MVC Framework
- For Business Layer
- Using Mockito
- For Data Layer
- Using Data JPA Test.
- One way to test sample data is to create data stubs of entities.
- Create a class with methods which contains methods which return different data structures of an entity.
- One function In class returns empty entity, another with Empty list of entity, Another with unique entity and another with list with single entity.
- Maintaining stubs Becomes difficult over time as data increases.
- Mocking helps us to overcome this problem.
- With mocks we can programmatically create classes.
- Create a mock of service class
- Create stubs for function responses using when.
- Assert the response
- Implement all methods.
- Check null returns.
- Check for number of Calls to methods.
- Spy the repository responses.
- Mock versus Spy
- Mocking creates a mock of the class all Calls I made on the mock of the class.Spy uses the real class.
- Null pointer exceptions will come wherever applicable in spy in mock we get null values in response
- For example, if we mock a list then while reading empty list We will get Null values. If we spy a list, then while reading empty list we will get Null pointer exception.
- Use spy where you want to use the original dependency for example, spy repositories.
- We can call verify on spy.
- When we don’t have access to a class and want to check what is going on in a Class, we use spy.
- https://github.com/gauravmatta/springmvc/blob/master/Unittesting/src/test/java/com/springimplant/unittesting/services/impl/ListMockTest.java
- Good Unit test cases
- Readable
- One look at test and we know what is being tested.
- 30 sec benchmark should be there
- Fast
- Since a unit test runs repeatedly, it should be fast.
- Isolated
- Fails only when there is an issue with Code.
- Should run often
- Testing with Junit
- Use assertEquals To compare two objects.
- Returns false if the objects differ.
- We may need to manually get and set values returned from dependencies as we can’t mock responses.
- We may need to create multiple stubs of service class and interfaces to inject data into tests.
- Keeping and maintaining stubs Is difficult as they need to be updated. Each time service changes are there.
- For junit 4 to execute a set of statements Before each test case create a method annotated by @Before
- For Junit 5 the annotation is @BeforeEach
- Testing with Mockito
- Used to mock results from dependencies injected such as Services or repositories.
- We can programmatically create classes with mocks.
- We can mock data service methods i.e we can create our assumed responses on mocking of methods.
- We can mock a class using mock keyword As follows.
- SomeDataService serviceMock = mock(SomeDataService.class).
- We can mock a method/function using when keyword as follows.
- when(serviceMock.returnAllValues()).thenReturn(new int[] {1,2,3};
- Instead of using static mock method to mock the classes We can also use annotation @InjectMocks or @Mock to create mocks.
- If we want to inject mocks via annotation we should use @RunWith(MockitoJunitRunner.class) annotation above class.
- @InjectMocks creates an Instance, class and injects the mocks that are Created with @Mock Annotation into this instance.
- We can return multiple/different values from the mock
- when(mock.size()).thenReturn(5).thenReturn(10).
- When First time we call or assert mock.size() It returns 5 Next time when we assert or Call, it returns 10.
- We can also return with parameters like
- When (mock.get(0)).thenReturn(“Spring Implant”)
- assertEquals(“Spring Implant”,mock.get(0)).
- assertEquals(null,mock.get(1)).
- We can also return with Generic parameters using Mockito For example
- when(mock.get(anyInt()).thenReturn(“Spring Implant”)
- assertEquals(“Spring Implant”,mock.get(0)).
- There are many other “any” Methods or argument marcher methods present in Mockito class.
- The Mockito class extends Argument Matchers class.
- We can also verify method Calls as follows
- String value = mock.get(0) is call to method.
- verify(mock).get(0)
- Check if get(0) is called in method at least once
- verify(mock).get(anyInt())
- Checks if get() with any int Param is called at least once.
- Verify(mock,times(1)).get(anyInt())
- Verify if mock.get(anyInt()) with any integer parameter is called at most once.
- Similarly we have verification like
- verify(mock,atMost(2)).get(anyInt()).
- Verify(mock,never()).get(2)
- Verify(mock,atLeastOnce()).get(anyInt())
- We can also capture arguments. For example, we have a method call as “mock.add(“Spring Implant”)
- We use ArgumentCaptor<String> To Capture the arguments for example
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class)
- Verify(mock).add(captor.capture());
- assertEquals(“Spring Implant”,captor.getValue());
- We can capture Arguments on multiple calls as well such as
- mock.add("Item1");
- mock.add("Item2");
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- verify(mock,times(2)).add(captor.capture());
- List<String> allValues = captor.getAllValues();
- assertEquals("Item1",allValues.get(0));
- assertEquals("Item2",allValues.get(1));
- We can also use spy instead of mock if we want to check Real class behaviour.
- In spy Original behaviour of class is retained.
- Only things we override our overridden by the characteristics that we specify.
- Whenever we want to use original class values, we use spy such as utility classes.
- For example
- ArrayList<String> arrayListSpy = spy(ArrayList.class);
- arrayListSpy.add("Item0");
- System.out.println(arrayListSpy.get(0));//Item0
- System.out.println(arrayListSpy.size());//1
- arrayListSpy.add("Item");
- arrayListSpy.add("Item1");
- System.out.println(arrayListSpy.size());//3
- when(arrayListSpy.size()).thenReturn(5);
- System.out.println(arrayListSpy.size());//5
- arrayListSpy.add("Item2");
- System.out.println(arrayListSpy.size());//5
- verify(arrayListSpy).add("Item2");
- Unit testing with spring boot and Mockito
- Controller Testing
- For Junit 4 Annotate the class with @RunWith(SpringRunner.class)
- Annotate the class with @WebMvcTest(HelloWorldController.class)
- Mock all services.
- Autowire MockMvc object in class
- Using MockMVC perform() method assert The response in a MVC Result object using andExpect() method.
MvcResult result = mockMvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().json("[{id: 3,name:Wickets,price:400,quantity:10},{id: 4,name:Bails,price:100,quantity:10}]"))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
- We test the endpoint, as follows.
- Check status is 200 or is OK.
- Check for content type and data.
- Check for Json content Using Content().json(jsonString)
- We can also use jsonAssert.assert Equals(expected,result.getResponse, Boolean string structure validation check).
- json.content internally uses jsonAssert.assertEquals with false json string structure validation check.
- Use MockBean to Mock all Beans.
- Stub all service methods using when() and thenReturn().
- https://github.com/gauravmatta/springmvc/blob/master/Unittesting/src/test/java/com/springimplant/unittesting/controller/HelloWorldControllerTest.java
- Using in memory database
- We should not use default database for unit test. If the database is down, we will have build failures.
- It is always better to use H2 database, which is in memory database.
- The following properties
- spring.jpa.show-sql =true
- spring.h2.console.enabled = true
- Writing test for business service
- InjectMock The service or service implementation Used by method and method is a part of.
- Mock the repository.
- Stub the repository methods.
- Using assert methods Perform validations.
- Writing test for Data Layer
- We only need to write test cases for our methods in Repository.
- We test the repository Methods.
- Annotate the class with @DataJPATest
- Load spring context.
- Annotate with @RunWith(SpringRunner.class) For junit4
- Autowire the repository.
- Write queries in file “data.sql” In resources folder To populate data in the database.
- Always use in memory database.
- Writing integration tests
- Use annotation @SpringBootTest
- Launches the entire spring boot application.
- Add parameter webEnvironment= WebEnvirnoment.RANDOM_PORT.
- Autowire TestRestTemplate.
- Use getForObject Method of the TestRestTemplate Class to Get String response end Point.
- Use Assert or JSONAssert to assert the response.
- We should use @MockBean To mock out dependencies, we do not wish to talk to.
- These may include Services/components which talk to external interfaces Like downstream systems or file systems, etc.
- We should never talk to real database, all external components that our system depends upon.
- Creating different test configuration
- Place a configuration properties file under src/test/resources.
- Annotate the test class with annotation @TestPropertySource(location={“classpath: testconfiguration.properties”})
- This helps us to use a particular configuration file for a test case.
- Writing unit tests For other request methods
- There are many request methods
- GET
- POST
- PUT
- DELETE
- There are variety of response status
- 200 - SUCCESS
- 404-RESOURCE NOT FOUND
- 400-BAD REQUEST
- 201-CREATED
- 401-UNAUTHORIZED
- 500-SERVER ERROR
- We can use Post method of MockMvcRequestBuilder To create a RequestBuilder object.
- We also need to provide request body content during the post method. We can provide that through content() method Of the RequestBuilder class.
- We can then execute the above RequestBuilder object using MockMVC perform method.
- We can check the status from the MockMvc expect() method as follows
- mockmvc.expect(status.isok()).
- Assertion Frameworks
- There are three frameworks which help us to write asserts.
- Hamcrest Matchers
- JsonAssert
- JsonPath
- Spring Boot starter Test library gets them all.
- Assertions with Hamcrest
- Update, eclipse static preferences with following libraries
- “org.hamcrest.CoreMatcher.*”
- “org.hamcrest.MatcherAssert.*”
- “org.hamcrest.Matchers.*”
- Following example shows asserting a list using Hamcrest matchers.
- Assertions with AssertJ
- In Eclipse in Preferences in Java ->Editor->content->favorites
- add org.assertJ.core.api.Assertions
- An example of asserting a list with AssertJ is as follows
- Assertions using JSONPath
- Used to Assert Json
- An example of asserting JSON using JSONPath is as follows.
- Measuring Test coverage
- Right click on project ->coverage as -> junit Test
- Analyses which lines in our source code are not covered by our unit test.
- A coverage report is a measure of Number of lines executed as a part of our unit test.
- Basically, all services, repositories and controller should be covered.
- Red lines in eclipse are not covered while green lines are covered.
- Coverage is not 100% measure of eliminating defects alone.
- Coverage should go along with Assets.
- Our unit test should run as fast as possible as they run each time our build runs.
- Recommendations
- Annotations
- Controllers
- Components
- Dependencies
- Documenting Java Code
- Entities
- Hibernate
- HTTPS Security
- Spring Core
- Maven
- Spring MVC
- Microservices
- Packages
- Project Configuration
- REST Templates
- Spring Boot
- AOP
- Spring DI
- Spring IOC
- Spring Data
- Tag Library
- View Resolvers
- Validations,Errors & Exceptions
- Activiti Framework
- Deploy spring boot Microservices in Fargate
- Spring Security
- Password encryption using Jasypt
- Flyway DB Migration Script
- Session in Spring Boot
- Spring Expression Language
- Spring JDBC
- Spring ORM
- Testing Spring Boot
- Correlation ID
- Logging
- ELK Stack
- EFK Stack
- Swagger
- Rabbit MQ
- Circuit Breaker Pattern
- Connection Pooling
- Spring Batch
- Zipkins
- Kafka
- Spring Boot Actuator
- Spring Cloud
- Caching
- Gateway
- Service Discovery
Testing Spring Boot
Subscribe to:
Posts (Atom)
Spring Boot
What is circular/cyclic dependency in spring boot? When two services are interdependent on each other, that is to start one service, we requ...
-
What is JPA? JPA Is also called as Java persistence API It is a standard form oracle to map object to database relations. Provides specific...
-
Technology's / frameworks in Spring Spring core Spring MVC Spring boot Spring data Hibernate
-
Q What is the minimal web version required to use JSTL? And : 2.4 For example following tag from web.xml uses web 4.0 <web-app xmlns:xs...
No comments:
Post a Comment