Annotation to log the execution time of each test case in Junit5 - time

I have a requirement to log the execution time for each test case. I don't want to use a custom implementation. I want to know whether there is an annotation available for this in junit5Btw, I know about Stopwatch or Junit4 #Timeout.

After a look through into junit5 documentation, I found this sample
TimeExtension
This snippet is from their docs:
#ExtendWith(TimingExtension.class)
class TimingExtensionTests {
#Test
void sleep20ms() throws Exception {
Thread.sleep(20);
}
#Test
void sleep50ms() throws Exception {
Thread.sleep(50);
}
}
EDIT: Source code for TimingExtension

I wrote a BenchmarkExtension that you can apply with #Benchmark. You can use it as follows:
#Benchmark
class BenchmarkTest {
#Test
void notBenchmarked() {
assertTrue(true);
}
#Test
#Benchmark
void benchmarked() throws InterruptedException {
Thread.sleep(100);
assertTrue(true);
}
}
When applied to the class you will get a single message with the total run time of all the tests methods in that class. When applied to a single test method, you will get a message for that test only.
I hope it will eventually find its way into JUnit Pioneer.

Junit5 also has a #Timout annotation.
There is also an assertTimeout and assertTimeoutPreemptively (see documentation).
Finally, the JUnit 4 Stopwatch functionality is not available in JUnit 5. Use TimeExtension as already mentioned. However this extension is not (yet?) part of the distribution (see issue 343).

If you are using Sonarqube, you can find time duration of each test and total of all test sorted by time
test time sorted
all test

There is nothing special that needs to be done to get the execution time for a test case in JUnit 5 - Jupiter.
The time is right there in the XML report.
On the 'testCase' element, there is a property 'time', which gives the time for execution of the test case. Below is an example. The times are in seconds
<testcase name="checkZKConnectivityWithAuth"
classname="test.zk.ZookeeperConnectionProviderTests"
time="7.177"/>
<testcase name="checkConfigRetrieval"
classname="test.zk.ZookeeperConnectionProviderTests"
time="0.213"/>
<testcase name="checkConfigInsertion"
classname="test.zk.ZookeeperConnectionProviderTests"
time="0.255"/>

Related

Mock a MDC data in spring boot test

I want to mock a data which is fetched from MDC in test class other wise when the code executed it return a null value. So i try below,
#RunWith(SpringRunner.class)
#SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.MOCK,classes = TestApp.class)
public class Test {
private MockMvc restMvc;
#Before
public void setUp() {
mock(MDC.class);
this.restMvc = MockMvcBuilders.standaloneSetup(TestController).build();
}
#Test
public void testMe() throws Exception {
when(MDC.get("correlation-id")).thenReturn("1234");
//Req param and header are intialized
restMvc.perform(get("/assignments").headers(headers).params(reqParams).principal(token).accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().is2xxSuccessful());
}
}
But i am getting error,
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
To mock a static method you should use Mockito.mockStatic method like this:
try (var mockStatic = Mockito.mockStatic(MDC.class)) {
mockStatic.when(() -> MDC.get("correlation-id"))
.thenReturn("1234");
// rest of the test...
}
You can read more about it in the Mockito documentation. Additionally, I've reproduced the problem and tested the solution - you can see a commit in a GitHub repository with all required code. Please note that usage of mockito-inline is required for this to work - see this part of the docs.
In case of your test, it would probably better to go with the approach proposed by #knittl in the comment - instead of mocking the get method, a value can be set in the MDC using the put method: MDC.put("correlation-id", "1234"). I've included both approaches in the GitHub repo mentioned before - both tests pass.

JaCoCo maven plugin not covering test for spring boot appplication

I have below method in my springboot application class, which fetch data from DB
public void load(){
Optional<List<Employee>> employee = employeeRepository.findEmployee();
// Some other code with employee data
}
I am writing some Junit 4 Test case for this method and also counting coverage with Jacoco plugin.
#RunWith(MockitoJUnitRunner.class)
public class EmployeeTest{
private EmployeeRepository employeeRepository = Mockito.spy(EmployeeRepository.class);
#Test
public void shouldLoadDataFromDB(){
EmployeeService employeeService = new EmployeeService(employeeRepository);
when(employeeRepository.findEmployee()).thenReturn(buildDataFromDB());
employeeService.load();
// Assertions
}
}
For above I am always getting code coverage 0 even though I have covered test for given method,also shows method is not not covered in test.
Can someone give some idea what am I missing here.
Edit
I have check in jacoco-session.html file, I don't see my classes there. How can I check what I am missing.
JaCoCo documentation saying class Id mismatch will also cause this issue but I don't understand how to check this.
Can you please help me on this.

Multiple runwith for a junit test class

Does any one know how to tackle this.
#RunWith(SpringJUnit4ClassRunner.class)
#RunWith(Parametrized.class)
#ContextConfiguration("/META-INF/blah-spring-test.xml")
public class BlahTest
..
so i want to have a spring nature test and at the same time want to have it parameterized to avoid code duplication ...
You can't use two runners as it noted in the commented post. You should use the Parameterized runner as use Spring's TestContextManager to load the Spring context.
#Before
public void before() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
As of Spring Framework 4.2, JUnit-based integration tests can now be executed with JUnit rules instead of the SpringJUnit4ClassRunner. This allows Spring-based integration tests to be run with alternative runners like JUnit’s Parameterized or third-party runners such as the MockitoJUnitRunner. See more details on spring doc.
Building upon John B's answer using TestContextManager, one can also call beforeTestMethod() and afterTestMethod() on it to better simulate SpringJUnit4ClassRunner's behaviour (for instance loading database with #Sql).
These methods require a Method parameter, so one can for instance take advantage of JUnit4's TestName rule to get the current test method's name and then retrieving it by reflection.
private static TestContextManager springTestContext
= new TestContextManager(BlahTest.class);
#Rule
public TestName testName = new TestName();
#Before
public void before() throws Exception {
springTestContext.prepareTestInstance(this);
springTestContext.beforeTestMethod(this,
getClass().getMethod(testName.getMethodName()));
}
#After
public void after() throws Exception {
springTestContext.afterTestMethod(this,
getClass().getMethod(testName.getMethodName()), null);
}

How to priortized the test cases in maven run?

I have 3 test cases i.e. 1 2 3. How will i give priority as 2 1 3 while executing maven command.
I assume you want to do it because you need some prerequisition prior the test can be run. You can do it by #Before Annotation prior the actual testcase, or you can call other tests from the test method.
Say, testClient() test will test and verify that new client can be added to the system. Then you can do this:
#Test
public void testWithdrawal(){
testClient(); // i need client existing before the test can be run
// ... do something else
}
In that case you have assured that prerequisites are fullfilled and dont have to worry much about the testcases order
EDIT
I think I understand your needs, because I am in quite similar situation. How I solved it:
For create I have special class, which can create me a data and return needed data. So, i have something like:
#Test
public void testShare(){
CreateTests create = new CreateTests; //This will just initialize the object
create.testCreate(); // this method can contain steps needed to create
String justCreatedEntity = create.getEntity(); // just example how you can use the just created entity in further tests
}
And my class to solve the create is something like this
public class CreateTests{
private static String entity; //static because i dont want it to be flushed when test ends
public void testCreate() throws Exception{
WebDriverBackedSelenium selenium = new WebDriverBackedSelenium(driver, "baseURL");
selenium.... // All the selenium stuff
setEntity(selenium.getText("id=mainForm.createdentity"));
}
public void setEntity(String ent){
this.entity = ent;
}
public String getEntity(){
return entity;
}
Its just an outline - but basically, I have these "crucial" entities as standalone objects, called by the test class. Inside test, i verify everything throgh getters. Like:
Assert.assertNotNull(create.getAuctionID(),"New Entity is NULL!" );
You can run mvn test with options to specify a single test, or multiple tests. The order they are run in is the order specified on the command line.
Reference is here: http://maven.apache.org/plugins/maven-surefire-plugin/examples/single-test.html
Note that Java suggests that the good unit testing practice of tests not requiring to be run in order and test to not rely on each other:
http://java.sun.com/developer/Books/javaprogramming/ant/ant_chap04.pdf

where is the [Duration] attribute in mbunit, for timing tests?

Is it gone from the latest version?
I want to see that a method doesn't deteriorate in its performance.
I forgot the technical term for it.
Have a look at the [Timeout] attribute. It might decorate test methods or test fixtures. The default value (when not specified) is 10 minutes.
[TestFixture]
public class Fixture
{
[Test, Timeout(60)] // timeout at 60 seconds
public void Method()
{
}
}

Resources