Unit Testing
•Unit testing means testing individual modules of an application in isolation (without any interaction with dependencies) to confirm that the code is doing things right. This type of testing is executed by the developers
Annotations
- @Test : Denotes that a method is a test method.
- @BeforeEach : Denotes that the annotated method should be executed before each
@Test
- @AfterEach : Denotes that the annotated method should be executed after each
@Test
- @Disabled : Used to disable a test class or test method;
Jacaco
- JaCaCo-Maven (abbreviation for Java Code Coverage) plugin is an open-source code coverage tool for Java. It also integrates smoothly with CI/CD tools.
- Jacaco Agent attaches to a JVM.
- Whenever a class is loaded, JaCoCo views when the class is called and what lines (of code) are called during the testing process. By keeping this track, it builds up the code coverage statistics.
- generate-report creates the file as soon as the JVM terminates.
TestDoubles
- The basic concept of mocking is replacing real objects with doubles.
- We can control how these doubles behave. These doubles we call test doubles.
- Mockito is a very popular library that allows us to create such mock objects.
@Mock, @Spy, @Stub, & @InjectMocks and @Captor
Mock
- The most widely used annotation in Mockito is @Mock. We can use @Mock to create and inject mocked instances
- A mock is a dummy class replacing a real one, returning something like null or 0 for each method call.
- You use a mock if you need a dummy instance of a complex class that would otherwise use external resources like network connections.
- The advantage of mocks is that you can isolate the class under test from the rest of the system.
Spy
A spy is kind of a hybrid between the real object and a stub, i.e. it is basically the real object with some (not all) methods shadowed by stub methods
Stub
A stub is a dummy class providing some more specific, prepared, or pre-recorded, replayed results to certain requests under test. You could say a stub is a fancy mock. To use stubs in JUnit you don’t need any frameworks. If you want to stub some interface just implement it
InjectMocks
@Mock
creates a mock. @InjectMocks
creates an instance of the class and injects the mocks that are created with the @Mock
(or @Spy
) annotations into this instance.
Captor
Use it to capture argument values for further assertions.
List mockList = Mockito.mock(List.class);
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
mockList.add("one");
Mockito.verify(mockList).add(arg.capture());
assertEquals("one", arg.getValue());
Junit Example
import com.jonesjalapat.blog.tradesman.persistence.dto.TradeResponse;
import com.jonesjalapat.blog.tradesman.persistence.repository.PersonRepository;
import com.jonesjalapat.blog.tradesman.persistence.repository.TradeRepository;
import com.jonesjalapat.blog.tradesman.persistence.repository.TradesmanRepository;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith({MockitoExtension.class})
class TradePersistenceServiceTest {
// System in Test
TradePersistenceService tradePersistenceService;
@Mock TradesmanRepository tradesmanRepository;
@Mock TradeRepository tradeRepository;
@Mock PersonRepository personRepository;
@BeforeEach
void setUp() {
tradePersistenceService =
new TradePersistenceService(tradesmanRepository, tradeRepository, personRepository);
}
@Test
public void getListOfTradesOfTradeTypeCarpenter() {
// GIVEN
String trade = "Carpenter";
TradeResponse tradeResponse = createTradeResponse();
Mockito.when(tradesmanRepository.findTradesmanByTrade(trade))
.thenReturn(Collections.singletonList(tradeResponse));
// WHEN
List<TradeResponse> response = tradePersistenceService.getListOfTrades(trade);
// THEN
Assertions.assertEquals(response.get(0).getType(), trade);
}
private TradeResponse createTradeResponse() {
TradeResponse tradeResponse = new TradeResponse();
tradeResponse.setType("Carpenter");
return tradeResponse;
}
}
Integration Testing
- Integration testing means checking if different modules are working fine when combined together as a group.
- Tests confirm that your API is working as expected, that integrations between services are functioning reliably, and that any changes haven’t broken existing functionality.
- You can write test scripts for your Postman API requests in JavaScript
Adding Tests
- You can add tests to individual requests, collections, and folders in a collection.
- To add tests to a request, open the request and enter your code in the Tests tab
- Tests will execute after the request runs. The output is in the response’s Test Results tab.
Collection Runner
- The Collection Runner enables you to run a collection’s requests in a specified sequence to test the functionality of your API.
- The Postman CLI is a secure command-line companion for Postman. It’s secured and supported by Postman.
- postman collection run /myCollectionFolderName/myCollectionFile.json
Performance Testing – JMeter
The Apache JMeter application is open-source software, a 100% pure Java application designed to load test functional behavior and measure performance.
Run Apache JMeter
- Download the binaries from https://jmeter.apache.org/download_jmeter.cgi
- Navigate to bin library and run ./jmeter.sh file
- Optionally, To override the default JVM configuration – JVM_ARGS=”-Xms2048m -Xmx4096m” ./jmeter.sh
Elements of Test Plan
Test Plan
A test plan describes a series of steps JMeter will execute when run. A complete test plan will consist of one or more Thread Groups, logic controllers, sample generating controllers, listeners, timers, assertions, and configuration elements.
Thread Group
Thread group elements are the beginning points of any test plan. All controllers and samplers must be under a thread group. Other elements, e.g. Listeners, may be placed directly under the test plan, in which case they will apply to all the thread groups. As the name implies, the thread group element controls the number of threads JMeter will use to execute your test. The controls for a thread group allow you to:
- Set the number of threads
- Set the ramp-up period
- Set the number of times to execute the test
Each thread will execute the test plan in its entirety and completely independently of other test threads. Multiple threads are used to simulate concurrent connections to your server application
Controllers
JMeter has two types of Controllers: Samplers and Logical Controllers. These drive the processing of a test.
Samplers: Samplers tell JMeter to send requests to a server and wait for a response. They are processed in the order they appear in the tree. Controllers can be used to modify the number of repetitions of a sampler.
Logic Controllers: let you customize the logic that JMeter uses to decide when to send requests. Logic Controllers can change the order of requests coming from their child elements. They can modify the requests themselves, cause JMeter to repeat requests, etc.
Listeners
Listeners provide access to the information JMeter gathers about the test cases while JMeter runs. The Graph Results listener plots the response times on a graph. The “View Results Tree” Listener shows details of sampler requests and responses, and can display basic HTML and XML representations of the response. Other listeners provide summary or aggregation information.
Additionally, listeners can direct the data to a file for later use. Every listener in JMeter provides a field to indicate the file to store data to. There is also a Configuration button which can be used to choose which fields to save, and whether to use CSV or XML format.
Timers
A timer will cause JMeter to delay a certain amount of time before each sampler which is in its scope. By default, a JMeter thread executes samplers in sequence without pausing.
Assertions
Assertions allow you to assert facts about responses received from the server being tested. Using an assertion, you can essentially “test” that your application is returning the results you expect it to.
Configuration Elements
A configuration element works closely with a Sampler, Although it does not send requests, it can add to or modify requests. For example, if you place an HTTP Cookie Manager inside a Simple Logic Controller, the Cookie Manager will only be accessible to HTTP Request Controllers you place inside the Simple Logic Controller).
Pre-Processor Elements
A Pre-Processor executes some action prior to a Sampler Request being made. If a Pre-Processor is attached to a Sampler element, then it will execute just prior to that sampler element running. A Pre-Processor is most often used to modify the settings of a Sample Request just before it runs, or to update variables that aren’t extracted from response text.
Post-Processor Elements
A Post-Processor executes some action after a Sampler Request has been made. If a Post-Processor is attached to a Sampler element, then it will execute just after that Sampler element runs. A Post-Processor is most often used to process the response data, often to extract values from it.
Execution Order
- Configuration elements
- Pre-Processors
- Timers
- Sampler
- Post-Processors (unless SampleResult is null)
- Assertions (unless SampleResult is null)
- Listeners (unless SampleResult is null)
Properties And Variables
JMeter properties are defined in jmeter.properties, Properties are global to jmeter, and are mostly used to define some of the defaults JMeter uses.
JMeter variables are local to each thread. The values may be the same for each thread, or they may be different. If a variable is updated by a thread, only the thread copy of the variable is changed. Note that the values defined by the Test Plan and the User Defined Variables configuration element are made available to the whole test plan at startup. If the same variable is defined by multiple UDV elements, then the last one takes effect.
Build an Load Testing Setup for Rest API
Step1 : Create a TestGroup to run the test
Step2 : Configure TestGroup with multiple threads
We start 10 threads to execute the API, the total duration the test would run is 100.
Step3 : Generate Access Credentials using logic Controller + Sampler + Configuration element
We will add Only Once controller(Logic Controller) which will be executed only the first time, subsequent iterations will skip it however each thread will run the controller once . Next, We add the HTTP request(sampler) and add credntial details. Also along with it, we add a Configuration element i.e csv data set config which will be used to read the authorities details in a multithread environment.
Step4 : Store the access token using Post Processor
Step5 : Configure an Rest API using logic Controller + Sampler
Add a Transaction Controller(logic controller), and then add HttpRequest to execute the Rest API with the url, post body etc.
Step6 : Add a Configuration Element for token
Add Http Header Manager which adds access token to Http Request.