Declaring Jmockit mock parameters on #BeforeMethod of TestNG - java

I've been testing my code behavior using TestNG and JMockit for a while now and I have had no specific issue with their combination. Today I came across a situation where I needed to mock one of my internal dependencies, in the so called, type wide manner and I did not need to keep that mock around since none of the test cases dealt with it directly while they counted on the mocked version functionality. So, naturally, I put the mocking logic in my #BeforeMethod. Here is a sample:
public class SampleTest
{
#Mocked
#Cascading
private InnerDependency dependency;
#BeforeMethod
public void beforeMethod()
{
new NonStrictExpectations()
{
{
dependency.getOutputStream((String)any);
result = new Delegate<OutputStream>()
{
public OutputStream getOutputStream(String url)
{
return null;
}
};
}
};
}
#Test
public void testNormalOperation()
{
// The test whose desired behavior depends on dependency being mocked out
// ..
}
}
But, since my tests do not care about the mocked dependency explicitly, I'm not willing to declare it as a test class field, unlike what is done above. To my knowledge of JMockit The only options remaining would be:
Declare dependency as a local mock field:
new NonStrictExpectations()
{
#Cascading
private InnerDependency dependency;
{
//...
}
}
Declare dependency as an input argument for beforeMethod(), similar to what is done for normal #Test methods:
#BeforeMethod
public void beforeMethod(#Mocked #Cascading final InnerDependency dependency)
{
// ...
}
I see that JMockit 1.6+ would not like the first option and warns with WARNING: Local mock field "dependency" should be moved to the test class or converted to a parameter of the test method. Hence, to keep everyone happy, I'm ruling this option out.
But for the second option, TestNG (currently 6.8.6) throws exception when running the test saying java.lang.IllegalArgumentException: wrong number of arguments. I don't see this behavior with normal #Test cases passed with #Mocked parameters. Even playing with #Parameter and #Optional will not help (and should not have!).
So, is there any way I could make this work without declaring the unneccessary test class mock field, or am I missing something here?
Thanks

Only test methods (annotated with #Test in JUnit or TestNG) support mock parameters, so the only choice here is to declare a mock field at the test class level.
Even if not used in any test method, I think it's better than having it declared in a setup method (using #Before, #BeforeMethod, etc.). If it were to be possible, the mock would still have to apply to all tests, because of the nature of setup methods; having a mock field of the test class makes it clear what the scope of the mock is.

Dynamic partial mocking is one more technique to specify #Mocked dependencies locally. However, it has it's limitations (see comments below).

Related

How to set Mock to have a default behavior and can override it in some test

I want to mock a dependency and return a default value in most test cases since most of them should not care about the values returned but there are some certain cases like I would like to test like the dependency returns some weird values or just throw. So I am modeling it in this way. Most cases, it should return a nice and valid value.
Test Setup which return the 20L by default for all test classes.
Dependency dependency = Mockito.mock(Dependency.class);
when(dependency.returnSomeVal()).thenReturn(20L);
In a specific test cases class, I would like to override the behavior like below:
when(dependency.returnSomeVal()).thenThrow(); //failure cases
when(dependency.returnSomeVal()).thenReturn(Weird_Val); //failure cases
But I don't find a good solution to override the existing behavior? Any idea?
You can reset the mock and add behavior. In the test, do
Mockito.reset(dependency);
when(dependency.returnSomeVal()).thenThrow(); //failure cases
when(dependency.returnSomeVal()).thenReturn(Weird_Val); //failure cases
Resetting will remove all mocked behavior on this class though. If you want to remock only some methods, then you have to create the mock from scratch.
I ended using myself this pattern to mock a bunch of methods of a class providing configurations.
In a #Before method I setup a bunch of stubs for a mocked object that provide a correct configuration for each test. Afterwards, in each test it was extremely convenient to only override one of those stubs to provide a different configuration and test a different error case.
I think the response from Hari Menon is correct but it somehow defeats the purpose explained in the question. If the mock is reset, all the stubs would need to be added again, making this pattern very confusing (it would be better to not use any overriding than using reset in this case, the code would be way more straightforward).
The comments added to the question provide indeed an indirect answer on how to achieve this, and why it works, but it took me a bit to get it working.
In spite of one of the comments, I made everything work by using in my #Before fixture when().thenReturn() and overriding the concrete stub with doReturn().when()
Example:
public class WorkerTest {
private ConfigProvider mockedConfigProvider = mock(ConfigProvider.class);
#Before
public void setup() {
// Setup stubs with a correct config
when(mockedConfigProvider.getValue("property1")).thenReturn("value1");
when(mockedConfigProvider.getValue("property2")).thenReturn("value2");
when(mockedConfigProvider.getValue("property3")).thenReturn("value3");
when(mockedConfigProvider.getValue("property4")).thenReturn("value4");
}
#Test
public void test_GoodConfig(){
// The config object gets injected in the test worker
Worker testWorker = new Worker(mockedConfigProvider);
// testWorker.execute() returns true if everything went well
assertTrue(testWorker.execute());
}
#Test
public void test_BadConfigProp1(){
// Test now with a broken 'property1', overriding that stub.
doReturn(null).when(mockedConfigProvider).getValue("property1");
Worker testWorker = new Worker(mockedConfigProvider);
// testWorker.execute() returns false if there is a problem.
assertFalse(testWorker.execute());
}
#Test
public void test_BadConfigProp2(){
// This test needs to only override the result of property2
doReturn("crazy result").when(mockedConfigProvider).getValue("property2");
...
}

How to reuse method and test in JUnit?

I've tried to avoid duplicate code in JUnit test, but I'm kind of stuck.
This is my first test, for the second one it has exactly the same methods but different service (different input). instead of the TestCaseResourceTest1 I have TestCaseResourceTest2. Now what could be the proper way to test both? I want to have a separate file for test number 2, how should I avoid the duplicate code? (ex. use the beforeFileTest() method)
public class TestCaseResourceTest1 {
#Mock
private TestService testService;
#Mock
private AreaService areaService;
private TestCaseService1 testCaseService1; // is changed in test2
#Before
public void before() throws Exception{
testCaseService1 = mock(TestCaseService1.class); // is changed in test2
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
private void beforeFileTest() throws Exception{
doReturn(true).when(areaService).chechExists(any(String.class), eq(false));
}
#Test
public void verifyFileExists() throws Exception{
verifyOtherArea(testCaseService1); // is changed in test2
doReturn(false).when(areaService).chechExists(any(String.class), eq(false));
}
}
just lines with comment is changed in test2 are differences.
Tnx
Given this excerpt from your question:
… instead of the TestCaseResourceTest1 I have TestCaseResourceTest2 … I want to have a separate file for test number 2
… the standard ways of sharing code between test cases are:
Create a Test Suite and include the shared code in the test suite (typically in #BeforeClass and #AfterClass methods). This allows you to (1) run setup code once (per suite invocation); (2) encapsulate shared setup/teardown code and (3) easily add more tests cases later. For example:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestCaseResourceTest1.class,
TestCaseResourceTest2.class
)}
public class TestSuiteClass {
#BeforeClass
public void setup() {
beforeFileTest();
}
private void beforeFileTest() throws Exception {
// ...
}
}
Create an abstract class which parents TestCaseResourceTest1 and TestCaseResourceTest2 and let those test cases call the shared code in the parent (typically via super() calls). With this approach you can declare default shared code in the parent while still allowing sub classes to (1) have their own behaviour and (2) selectively override the parent/default behaviour
Create a custom JUnit runner, define the shared behaviour in this runner and then annotate the relevant test cases with #RunWith(YourCustomRunner.class). More details on this approach here
Just to reiterate what some of the other posters have said; this is not a common first step so you may prefer to start simple and only move to suites or abstract classes or custom runners if your usage provides a compelling reason to do so.
I had the such situation and it was a sign about wrong implementation design. We are talking about pure unit tests where we test exactly what is implemented in the production classes. If we need duplicated tests it means we probably have duplication in implementation.
How did I resolve it in my project?
Extracted common logic into parent service class and implemented unit tests for it.
For child services I implemented tests only for particular implemented code there. No more.
Implemented an integration tests on real environment were both services were involved and tested completely.
Assuming you want to have the exact same test run for 2 different classes (and not mocking it as in your example code), you can create an abstract test class, that has abstract method that returns an instance of the class to be tested.
Something in the vein of:
public abstract class TestCaseResourceTest {
protected abstract TestCaseService1 getServiceToTest();
#Before
public void before() throws Exception {
testCaseService1 = getServiceToTest();
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
#Test
public void test() {
// do your test here
}
}
public class ConcreteTest extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new TestCaseService();
}
}
public class ConcreteTest2 extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new DifferentService();
}
}
Have you considered using JUnit 5 with its http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests ?
It allows you to re-use your tests with different input. This is an example from the documentation which illustrates what you can do now with JUnit 5:
#ParameterizedTest
#ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
But you can also create your methods which return the input data:
#ParameterizedTest
#MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
Here I am using just strings, but you can really use any objects.
If you are using Maven, you can add these dependencies to start using JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0-RC2</version>
<scope>test</scope>
</dependency>
The only annoying thing about JUnit 5 is that it is not released yet.
When going from one test to two tests, you don't know what will be duplicate code, so I find it useful to put everything into one test method. In this case, start by putting the contents of the #Before and beforeFileTest methods inline in the test.
Then you can see that it is just te service that needs changing, so you can extract everything except that into a helper method that is called from two tests.
Also, after you have two tests that are calling the same helper method and are happy with that test coverage, you could look into writing parameterized tests. For example with JunitParams: https://github.com/Pragmatists/junitparams/wiki/Quickstart

Mocking Static method using PowerMockito

I am using PowerMockito to mock a static method to get a better line coverage. The test passes but Cobertura still shows the return line as red. I am not sure if I am using PowerMockito in a wrong way. Any clues?
MUT
public static Object getBean( String beanName ) {
return AppContext.getApplicationContext().getBean( beanName );
}
Junit test
#RunWith ( PowerMockRunner.class )
#PrepareForTest ( {AppContext.class} )
private ApplicationContext applicationContext;
#Test
public void testGetBean() throws Exception {
String beanName = "junitBean";
applicationContext = Mockito.mock(ApplicationContext.class);
PowerMockito.mockStatic(AppContext.class);
AppContext.setApplicationContext(applicationContext);
PowerMockito.when(AppContext.getApplicationContext()).thenReturn(applicationContext);
PowerMockito.when(AppContext.getApplicationContext().getBean(beanName)).thenReturn(Object.class);
AppContext.getBean(beanName);
}
To mock static methods, PowerMock has to modify the Java Byte Code of your class after it has been compiled. Code coverage tools work in the same way - they "instrument" (google for "bytecode instrumentation") the bytecode in order to collect information about which lines of code have been run.
Given that there are two things here modifying already compiled code according to their own needs, it's not surprising that they don't work well together. In fact, other coverage tools have the same issue e.g. this issue on the PowerMock GitHub page.
It is precisely reasons like this that mocking static methods is a bad idea and should only really be done in very exceptional circumstances. In most cases, you can either wrap the static method call in an interface and pass an instance of the interface to your object under test, or better yet (if the code is under your control) remove the static method and replace it with an instance method.
You could also just pass the ApplicationContext instance directly into the constructor of your class under test.

How to make the unit test execute a particular test case everytime when it sees a certain function in the executing java project?

I am having a build failure issue while running a bunch of unit test over a java project. I am getting the NoClassDefFoundError which is happening because of the lack of ability for the unit test to get the dependencies. I am trying to mock an object for the class and then call the function, but the code is structured in a way that is getting a bit complex for me to handle the issue. I am very new to unit testing. I have provided below, a sample of code structure that my project has
Class ServiceProvider(){
obj declarations;
public void mainFunction(){
//Does a couple of things and calls a function in another class
boolean val = subFunction();
}
public boolean subFunction(){
boolean val = AnotherClass.someFunction(text);
//this function throws lots of exceptions and all those are caught and handled
return val;
}
#RunsWith(MockitoJUnitRunner.class)
Class UnitTestBunch(){
#Mock
AnotherClass acObj = new AnotherClass();
#InjectMock
ServiceProvider sp = new ServiceProvider();
#Test
public void unitTest1() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
#Test
public void unitTest2() throws Exception{
thrown.expect(ExceptionName.Class);
sp.mainFunction();
}
I have a test that uses the mock object and performs the function call associated with that class. But, the issue here is that there are a bunch of other unit test cases that are written similar to the unitTest2 function and calls the mainFunction at the end of the test. This mainFunction invokes someFunction() and causes NoCalssDefFoundError(). I am trying to make the unit test execute the content in unitTest1 everytime when it sees the AnotherClass.someFunction(). I am not sure if this is achievable or not. There could be another better way to resolve this issue. Could someone please pitch in some ideas?
In your test you seem to be using unitTest1 for setup, not for testing anything. When you run a unit test, each test should be able to run separately or together, in any order.
You're using JUnit4 in your tests, so it would be very easy to add the statement you have in unitTest1 into a #Before method. JUnit4 will call this method before each test method (annotated with #Test).
#Before
public void stubAcObj() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
The method may be named anything, though setUp() is a common name borrowed from a method to override in JUnit3. However, it must be annotated with org.junit.Before.
If you need this from multiple test cases, you should just create a helper, as you would with any code. This doesn't work as well with #InjectMocks, but you may want to avoid using #InjectMocks in general as it will fail silently if you add a dependency to your system-under-test.
public class AnotherClassTestHelper {
/** Returns a Mockito mock of AnotherClass with a stub for someFunction. */
public static AnotherClass createAnotherClassMock() {
AnotherClass mockAnotherClass = Mockito.mock(AnotherClass.class);
when(mockAnotherClass.someFunction(text)).thenReturn(true);
return mockAnotherClass;
}
}
As a side note, this is a counterintuitive pattern:
/* BAD */
#Mock
AnotherClass acObj = new AnotherClass();
You create a new, real AnotherClass, then instruct Mockito to overwrite it with a mock (in MockitoJUnitRunner). It's much better just to say:
/* GOOD */
#Mock AnotherClass acObj;

Non static #BeforeClass equivalent when Spring unit test runner? [duplicate]

Are there any best practices to get Junit execute a function once in a test file , and it should also not be static.
like #BeforeClass on non static function?
Here is an ugly solution :
#Before void init(){
if (init.get() == false){
init.set(true);
// do once block
}
}
well this is something i dont want to do , and i am looking for an integrated junit solution.
A simple if statement seems to work pretty well too:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {
public static boolean dbInit = false;
#Autowired
DbUtils dbUtils;
#Before
public void setUp(){
if(!dbInit){
dbUtils.dropTables();
dbUtils.createTables();
dbInit = true;
}
}
...
To use an empty constructor is the easiest solution. You can still override the constructor in the extended class.
But it's not optimal with all the inheritance. That's why JUnit 4 uses annotations instead.
Another option is to create a helper method in a factory/util class and let that method do the work.
If you're using Spring, you should consider using the #TestExecutionListeners annotation.
Something like this test:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({CustomTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
#ContextConfiguration("test-config.xml")
public class DemoTest {
Spring's AbstractTestExecutionListener contains for example this empty method that you can override:
public void beforeTestClass(TestContext testContext) throws Exception {
/* no-op */
}
NOTE: DO NOT overlook/miss DependencyInjectionTestExecutionListener while adding custom TestExecutionListeners. If you do, all the autowires will be null.
If you don't want to set up static initializers for one time initialization and are not particular about using JUnit, take a look at TestNG. TestNG supports non-static, one-time initialization with a variety of configuration options, all using annotations.
In TestNG, this would be equivalent to:
#org.testng.annotations.BeforeClass
public void setUpOnce() {
// One time initialization.
}
For teardown,
#org.testng.annotations.AfterClass
public void tearDownOnce() {
// One time tear down.
}
For the TestNG equivalent of JUnit 4's #Before and #After, you can use #BeforeMethod and #AfterMethod respectively.
Easily use #BeforeAllMethods/#AfterAllMethods annotations to run a method inside the instance context (non-static), where all injected values will be available.
There is a special testing library for this:
https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0
https://bitbucket.org/radistao/before-after-spring-test-runner/
The only limitation: works only for Spring testing.
(I'm the developer of this testing library)
I've never tried but maybe you can create a no-argument constructor and call you function from there?
The article discuss 2 very nice solutions for this problem:
"clean" junit with custom Runner (using interface but you could extend it with a custom annotation e.g. #BeforeInstance)
Spring execution listeners as mentioned by Espen before.
UPDATE: Please see the comment by Cherry for why the suggestion below is flawed. (Am keeping the answer on here rather than deleting as the comment may provide useful information to others as to why this doesn't work.)
Another option worth considering if using dependency injection (e.g. Spring) is #PostConstruct. This will guarantee dependency injection is complete, which wouldn't be the case in a constructor:
#PostConstruct
public void init() {
// One-time initialization...
}
Just use #BeforeClass:
#BeforeClass
public static void init() {
}
It doesn't make sense for init to be non-static because each test is run in a separate instance. The instance
that init is run on would not match the instance of any test.
The only reason that you might want it to be non-static is to override it in subclasses, but you can do this
with static methods too. Just use the same name, and only the subclass init method will be called.

Categories