Is it possible to create nested unit test using junit and mockito? - java

For example:
#RunWith(MockitoJUnitRunner.class)
public class ClientFormServiceTest {
#Mock
ClientFormService clientFormService;
public class GetNewClientFormTest {
#Mock
protected ClientForm result;
#Before
public void given() {
result = clientFormService.getNewForm();
}
#Test
public void should_do_something() {
}
}
public class CreateClientFormTest {
#Mock
protected ClientForm clientForm;
#Before
public void given() {
clientFormService.createForm(clientForm);
}
#Test
public void should_do_something() {
}
}
}
This is what I want to do but I can't run the unit tests if are nested to a class.

I'm the author of a JUnit TestRunner, junit-nested, which I believe may do what you want: https://github.com/avh4/junit-nested
However, from your example it's not clear why you need nested tests. The typical reason to use them is to share setup behavior, but you should consider if having separate test classes is more appropriate.
In any case, here's how you can do it with junit-nested: (Since Nested is a test runner, you'll have to use MockitoAnnotations.initMocks() instead of the Mockito test runner.)
import net.avh4.test.junit.Nested;
#RunWith(Nested.class)
public class ClientFormServiceTest {
#Mock
ClientFormService clientFormService;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
}
public class GetNewClientFormTest {
#Mock
protected ClientForm result;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
result = clientFormService.getNewForm();
}
#Test
public void should_do_something() {
}
}
public class CreateClientFormTest {
#Mock
protected ClientForm clientForm;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
clientFormService.createForm(clientForm);
}
#Test
public void should_do_something() {
}
}
}

Why would you like to do that? If you mean to benefit from code reuse among many similar tests, you could come up with a base test class with common code and make test classes extend it.

Related

JUnit test for ApplicationReadyEvent in spring boot app

I tried to write test for my spring boot application.
My application has business logic, which start after spring app has been initialized.
There is need to test triggeration of method with annotation #EventListener(ApplicationReadyEvent.class)
Below is a simple example that doesn't work. I expect that inscription "Testing..." appears in the console.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
MySpringBootTest.MyTestConfig.class
})
public class MySpringBootTest {
#Test
public void test() {
}
#Configuration
public static class MyTestConfig {
#EventListener(ApplicationReadyEvent.class)
public void init() {
System.out.println("Testing...");
}
}
}
how do I make this example work?
Because you are using #ContextConfiguration Spring application Context is partially loaded and you don't have access to every capability of Spring application Context, however There are many ways to achieve something you want to do. One of them is using TextExecutionListener. I will show you how to use that in both Junit 4 and Junit 5 (jupiter):
Junit 5 (jupiter):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes= MySpringBootTest.MyTestConfig.class)
#TestExecutionListeners(listeners = {MySpringBootTest.MyTestConfig.class})
public class MySpringBootTest {
#Test
public void test1() {
....
}
#Test
public void test2() {
...
}
#Configuration
public static class MyTestConfig extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("Testing...");
testContext.getApplicationContext(); //Do anything you want here
}
}
}
Here is a quote from Java doc for beforeTestClass method of TestExecutionListener:
Pre-processes a test class before execution of all tests within
the class. This method should be called immediately before
framework-specific before class lifecycle callbacks.
From the testContext that will be passed to this method you will have access to the application context and test class itself, you can do every thing you want with the test class there.
Junit 4:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MySpringBootTest.MyTestConfig.class})
#TestExecutionListeners(listeners = {MySpringBootTest.CustomTestExecutionListener.class,
SpringBootDependencyInjectionTestExecutionListener.class})
public class MySpringBootTest {
#Test
public void test1() {
....
}
#Test
public void test2() {
...
}
#Configuration
public static class MyTestConfig {
}
public static class CustomTestExecutionListener extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("Testing...");
testContext.getApplicationContext(); //Do anything you want here
}
}
}

JUnit parameterized and non-parameterized tests with PowerMockito

So I am trying to run JUnit parameterized tests along with non-parameterized tests in the same test class. But I am running into one error or the other. Has anyone tried this before and were they successful in doing so? I know other runners need to be used with the #PowerMockRunnerDelegate in order to run correctly. So here's what I came up with:
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(Enclosed.class)
#PrepareForTest(Some.class)
#PowerMockIgnore("javax.management.*")
public class TestClass {
#PowerMockRunnerDelegate(Parameterized.class)
public static class ParameterizedTests {
}
#Test
public void nonParameterizedTestOne() {
}
#Test
public void nonParameterizedTestTwo() {
}
}
But I get the error:
Test class should have exactly one public zero-argument constructor
Without powermock, this situation can be easily handled with:
#RunWith(Enclosed.class)
public class TestClass {
#RunWith(Parameterized.class)
public static class ParameterizedTests {
}
#Test
public void nonParameterizedTestOne() {
}
#Test
public void nonParameterizedTestTwo() {
}
}
But I would definitely like to use powermock. Any solutions?
I had the same issue, this worked for me:
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(Enclosed.class)
#PrepareForTest({Some.class})
public class TestClass {
private static void setUpOnceForAllTests() {
}
private static void setUpForEveryTest() {
}
public static class SingleTests {
// Setup once for all single tests
#BeforeClass
public static void setUpBeforeClass() {
setUpOnceForTests();
}
// Setup for each and every single test
#Before
public void setUp() {
setUpForEveryTest();
}
#Test
public void nonParameterizedTestOne() {
}
#Test
public void nonParameterizedTestTwo() {
}
}
#PowerMockRunnerDelegate(Parameterized.class)
public static class ParameterizedTests {
// Setup once for all parameterized test
#BeforeClass
public static void setUpBeforeClass() {
setUpOnceForTests();
}
// Setup for each and every parameterized test
#Before
public void setUp() {
setUpForEveryTest();
}
#Parameterized.Parameters
public static Collection<Enum> param() {
return new ArrayList<>(Arrays.asList(Enum.values()));
}
#Parameterized.Parameter
public int param;
#Test
public void parameterizedTestOne() {
}
#Test
public void parameterizedTestTwo() {
}
}
}

How to Unit Test a Utility Class with Powermockito in Java

I've seen how to unit test classes that use Utility classes by mocking the Static method, but I haven't been able to figure out how to unit test the actual Utility Class.
Here is the Utility Class
public class DbNameContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDbName(String dbName){
contextHolder.set(dbName);
}
public static String getDbName(){
return (String) contextHolder.get();
}
public static void clearDbName(){
contextHolder.remove();
}
}
Here is what I've tried so far for a unit test
#RunWith(PowerMockRunner.class)
#PrepareForTest({DbNameContextHolder.class, ThreadLocal.class})
public class DbNameContextHolderTest {
#SuppressWarnings("rawtypes")
#Mock
ThreadLocal threadLocalMock;
#Before
public void init() throws Exception{
PowerMockito.whenNew(ThreadLocal.class).withNoArguments().thenReturn(threadLocalMock);
}
#Test
public void setsDBName(){
DbNameContextHolder.setDbName("someName");
verify(threadLocalMock).set("someName");
}
#Test
public void getsDbName(){
DbNameContextHolder.getDbName();
verify(threadLocalMock).get();
}
#Test
public void clearsDBName(){
DbNameContextHolder.clearDbName();
verify(threadLocalMock).remove();
}
}
How do I mock a utility class like this?
Using the suggestions in the comments I've tested the expected outcome.
#RunWith(MockitoJUnitRunner.class)
public class DbNameContextHolderTest {
#Test
public void setsAndGetsDBNameCorrectly(){
DbNameContextHolder.setDbName("someName");
String returnedName = DbNameContextHolder.getDbName();
assertEquals("someName",returnedName);
}
#Test
public void clearsDBName(){
DbNameContextHolder.setDbName("someName");
String returnedName = DbNameContextHolder.getDbName();
assertEquals("someName",returnedName);
DbNameContextHolder.clearDbName();
returnedName = DbNameContextHolder.getDbName();
assertNull(returnedName);
}
}

SetUp/TearDown methods in sahi tests using junit framework

Is it possible to place the setup/teardown methods using JUnit framework in a single class (which would be my baseclass) so on test runs they methods are always called first/last? it would be in a similar way to which nunit tests can be structured
currently the only way I can get my tests to kick off is if I have the setup/teardown methods within the same class as my tests are (which is something I wan't to avoid, to keep my test classes tidy)
example I would hope to set up;
public class baseclass
{
#Before
public void setUp
{}
#After
public void tearDown
{}
}
public class tests
{
#Test
public void test1
{
// test content here
}
}
Run this test and see the sequence of events
class Test1 {
#Before
public void setUp1() {
System.out.println("setUp1");
}
}
public class Test2 extends Test1 {
#Before
public void setUp2() {
System.out.println("setUp2");
}
#Test
public void test() {
System.out.println("test");
}
}
Yes, as long as your test class extend your baseclass.
For instance:
Suite
#RunWith(Suite.class)
#SuiteClasses(Tests.class)
public class AllTests {
}
BaseClass
public class BaseClass {
#BeforeClass
public static void beforeAll() {
}
#Before
public void setUp() {
}
#After
public void tearDown {
}
#AfterClass
public static void afterAll() {
}
}
Tests
public class Test extends BaseClass {
#Test
public void test1() {
}
#Test
public void test2() {
}
}

How to call real methods in class instances annotated with #Injectable in JMockit?

I'm looking for a way in JMockit to inject the private fields inside a class while maintaining the ability to trigger the real methods. I use #Injectable and #Tested offered by JMockit. But somehow after that the injected instance is not able to call the real method.
Example test:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
doSomething.execute();
}
}
Here DoSomething wraps the Call instance, which provides a way to print a message. The ideal output of the four test cases would be:
real
real
real
fake
However the actual scenario is that only 3 and 4 worked, printing:
real
fake
This shows if an instance is created using #Injectable. It's not able to directly call the original method without copying and pasting the old method body to the mocked version. That seems really awkward. Is there a workaround of this?
My understanding is that if you use #Injectable you just get an empty mock and then you can no longer call the original method.
The workaround that I would use is to do the injection "manually" like this:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
//#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
}
I ran into this question when I had the same problem. However, the existing answer don't work with newer versions of JMockit.
If a field in the tested class is annotated with #Inject, a corresponding #Injectable is required in the test class. Usually. This means that removing the #Injectable and instead mock the class with MockUp suggested in the other answer doesn't work. JMockit will complain with "Missing #Injectable for field ...".
What needs to be done instead is to change the #Injectable annotation to a #Tested annotation, i.e. change this
#Injectable Call call;
to
#Tested Call call;
call becomes a real instance and JMockit doesn't complain about a missing #Injectable. If you need to mock some methods in call, it can be done with MockUp as usual.
new MockUp<Call>() {
#Mock
public void someMethodToMock() {
}
};

Categories