Unit Testing Scheduler job in java - java

We have a cron based job in our application.
The job class is as follows:
public class DailyUpdate implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
testMethod();
}
private void testMethod()
{
System.out.pritnln("Executed From scheduler");
}
}
How should we write unit test case to test Method
testMethod()
I cannot call testMethod Directly without scheduler as it is private..Any suggestion how to write unit test cases for Scheduler

In order to write a test you need to have an expected behavior so there is no point on testing a method that does nothing.
Now to your main problem. If you have somewhat of a legacy application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
So you can use the following pattern
Method testMethod = DailyUpdate.getDeclaredMethod(testMethod, argClasses);
testMethod .setAccessible(true);
return testMethod.invoke(targetObject, argObjects);
see also this question how to test a class that has private methods fields or inner classes

If you have the opportunity, I would suggest you to use PowerMock (instead of coding it by yourself).
Here is a link explaining how to use it : How to mock private method for testing using PowerMock?

Related

Spring Mockito Mocked object keeps calling real method [duplicate]

I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.

What use is #TestInstance annotation in JUnit 5?

Can you give a simple explanation of #TestInstance annotation and how it is useful in JUnit 5?
I think we can achieve the same effect probably by making our fields static.
I think the docs provide a useful summary:
If you would prefer that JUnit Jupiter execute all test methods on the same test instance, simply annotate your test class with #TestInstance(Lifecycle.PER_CLASS). When using this mode, a new test instance will be created once per test class. Thus, if your test methods rely on state stored in instance variables, you may need to reset that state in #BeforeEach or #AfterEach methods.
The "per-class" mode has some additional benefits over the default "per-method" mode. Specifically, with the "per-class" mode it becomes possible to declare #BeforeAll and #AfterAll on non-static methods as well as on interface default methods. The "per-class" mode therefore also makes it possible to use #BeforeAll and #AfterAll methods in #Nested test classes.
But you've probably read that already and you are correct in thinking that making a field static will have the same effect as declaring the field as an instance variable and using #TestInstance(Lifecycle.PER_CLASS).
So, perhaps the answer to the question "how it could be useful in JUnit 5" is that using a #TestInstance ...
Is explicit about your intentions. It could be assumed that use of the static keyword was accidental whereas use of #TestInstance is less likely to be accidental or a result of thoughless copy-n-paste.
Delegates the responsibility for managing scope and lifecycle and clean up to the framework rather than having to remember to manage that yourself.
This annotation was introduced to reduce the number of objects created when running your unit tests.
Adding #TestInstance(TestInstance.Lifecycle.PER_CLASS) to your test class will avoid that a new instance of your class is created for every test in the class.
This is particulary usefull when you have a lot of tests in the same test class and the instantiation of this class is expensive.
This annotation should be used with caution. All unit tests should be isolated and independent of eachother. If one of the tests changes the state od the test class then you should not use this feature.
Making your fields static to achieve the same effect is not a good idea. It will indeed reduce the number of objects created but they cannot be cleaned up when all tests in the test class are executed. This can cause problems when you have a giant test suite.
#TestInstance is used to configure the lifecycle of test instances for the annotated test class or test interface:
PER_CLASS: A new test instance will be created once per test class.
PER_METHOD: A new test instance will be created for each test method, test factory method, or test template method. This mode is analogous to the behavior found in JUnit versions 1 through 4.
If #TestInstance is not explicitly declared on a test class or on a test interface implemented by a test class, the lifecycle mode will implicitly default to PER_METHOD.
Setting the test instance lifecycle mode to PER_CLASS enables the following features:
Shared test instance state between test methods in a given test class as well as between non-static #BeforeAll and #AfterAll methods in the test class.
Declaration of #BeforeAll and #AfterAll methods in #Nested test classes.
Declaration of #BeforeAll and #AfterAll on interface default methods.
Simplified declaration of #BeforeAll and #AfterAll methods in test classes implemented with the Kotlin programming language.
See the test instance lifecycle documentation for further details.
since no one provide a proper coding example, I would like to give a simple code sample as below to understand the concept,
Per Method Sample - Default Option in Junit5
Note two methods are static, otherwise it will fire an exception because class instantiate in each method.
#TestInstance(Lifecycle.PER_METHOD)
public class MathUtilTestPerMethod {
MathUtil util;
#BeforeAll
static void beforeAllInit() {
System.out.println("running before all");
}
#AfterAll
static void afterAllCleanUp() {
System.out.println("running after all");
}
#BeforeEach
void init() {
util = new MathUtil();
System.out.println("running before each...");
}
#AfterEach
void cleanUp() {
System.out.println("running after each...");
}
#Test
void testSum() {
assertEquals(2, util.addtwoNumbers(1, 1));
}
}
Per Class Sample
Note that static is removed from the two methods and MathUtil object is created globally not in a method, because class instantiate only once.
#TestInstance(Lifecycle.PER_CLASS)
public class MathUtilTestPerClass {
MathUtil util = new MathUtil();
#BeforeAll
void beforeAllInit() {
System.out.println("running before all");
}
#AfterAll
void afterAllCleanUp() {
System.out.println("running after all");
}
#BeforeEach
void init() {
System.out.println("running before each...");
}
#AfterEach
void cleanUp() {
System.out.println("running after each...");
}
#Test
void testSum() {
assertEquals(2, util.addtwoNumbers(1, 1));
}
}
This is also useful when writing tests in Kotlin (because it doesn't have static methods).
So, instead of using a companion object with #JvmStatic funs in it for #BeforeAll or #AfterAll, make the lifecycle PER_CLASS and annotate regular methods with #BeforeAll or #AfterAll:
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {
#BeforeAll
fun setup() {
println("I am invoked only once")
}
}
When using this approach, be careful to reset your instance variables in #BeforeEach or #AfterEach funs if necessary.
Thanks to this article for its help.

What is the equivalent of TestName rule in JUnit 5?

How can I get name of the test method in JUnit 5?
Declare a parameter of type TestInfo in your test method and JUnit will automatically supply an instance of that for the method:
#Test
void getTestInfo(TestInfo testInfo) { // Automatically injected
System.out.println(testInfo.getDisplayName());
System.out.println(testInfo.getTestMethod());
System.out.println(testInfo.getTestClass());
System.out.println(testInfo.getTags());
}
You can get test method name (and more) from the TestInfo instance as shown above.
In addition to what is written about injecting TestInfo to test method it is also possible to inject TestInfo to methods annotated with #BeforeEach and #AfterEach which might be useful sometimes:
#BeforeEach
void setUp(TestInfo testInfo) {
log.info(String.format("test started: %s", testInfo.getDisplayName());
}
#AfterEach
void tearDown(TestInfo testInfo) {
log.info(String.format("test finished: %s", testInfo.getDisplayName());
}
An alternative for having the test name globally available as was possible in JUnit 4 is to shim the functionality yourself in a setup method using the TestInfo interface.
From the JUnit documentation on "Dependency Injection for Constructors and Methods":
The TestInfo can then be used to retrieve information about the current container or test such as the display name, the test class, the test method, and associated tags.
Here we leverage the fact that the built-in resolvers will supply an instance of TestInfo corresponding to the current container or test as the value for parameters of type TestInfo to methods annotated as lifecycle hooks (here we use #BeforeEach).
import org.junit.jupiter.api.TestInfo;
public class MyTestClass {
String displayName;
#BeforeEach
void setUp(TestInfo testInfo) {
displayName = testInfo.getDisplayName();
// ... the rest of your setup
}
}
This for example enables you to reference the current test name in other non-test methods (such as various utility methods) without having to include the test name as a parameter to each function call from the initial test method to that utility method.
You can do the same for other information about the current container or test.
Seems like the only disadvantages are:
the instance variable cannot be made final, as it is set dynamically
may pollute your setup code
For reference, here is how the TestName-Rule might be implemented in JUnit 4:
public class MyTestClass {
#Rule
public final TestName name = new TestName();
}

Exclude individual test from 'before' method in JUnit

All tests in my test class execute a 'before' method (annotated with JUnit's #Before) before the execution of each test.
I need a particular test not to execute this before method.
Is there a way to do it?
You can do this with a TestRule. You mark the test that you want to skip the before with an annotation of some description, and then, in the apply method in the TestRule, you can test for that annotation and do what you want, something like:
public Statement apply(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
if (description.getAnnotation(DontRunBefore.class) == null) {
// run the before method here
}
base.evaluate();
}
};
}
Consider using the #Enclosed runner to allow you to have two inner test classes. One with the required #Before method, the other without.
Enclosed
#RunWith(Enclosed.class)
public class Outer{
public static class Inner1{
#Before public void setup(){}
#Test public void test1(){}
}
public static class Inner2{
// include or not the setup
#Before public void setup2(){}
#Test public void test2(){}
}
}
Unfortunately you have to code this logic. JUnit does not have such feature.
Generally you have 2 solutions:
Just separate test case to 2 test cases: one that contains tests that require "before" running and second that contains tests that do not require this.
Implement your own test running and annotate your test to use it. Create your own annotation #RequiresBefore and mark tests that need this with this annotation. The test runner will parse the annotation and decide whether to run "before" method or not.
The second solution is clearer. The first is simpler. This is up to you to chose one of them.
This question has been asked a while ago, nevertheless, I would like to share my solution:
Annotate the desired method with #Tag("skipBeforeEach")
In your setup() method:
#BeforeEach
void setup(final TestInfo info) {
final Set<String> testTags = info.getTags();
if(testTags.stream()
.filter(tag->tag.equals("skipBeforeEach"))
.findFirst()
.isPresent()){
return;
}
// do your stuff
}```
I was looking for a solution to this problem and bumped into this question. As an update, in JUnit 5 this can be easily accomplished now with the use of the #Nested annotation.
If you are using Mockito, particularly Mockito 3.0, all stubbings will be "strict" and be validated by default.
You could use the Mockito lenient() method.
More here: https://www.baeldung.com/mockito-unnecessary-stubbing-exception#lenient-stubbing
One can also solve this by undoing what was done in #Before setup inside test case.
This is how it may look,
#Before
public void setup() {
TestDataSetupClass.setupTestData();
}
#Test
public void testServiceWithIgnoreCommonSetup() {
TestDataSetupClass.unSet();
//Perform Test
}
There will be pros and cons for solutions here. Minor con for this is, unnecessary cycle of setting and un-setting step. But goes well if one needs to do it for only a test case out of hundreds and avoid overhead of writing self AOP or maintaining multiple inner test classes.
If you have a #After method can clear the work done in #Before, you can manually call the #After method at the begining of your #Test method.

Mockito: Mocking "Blackbox" Dependencies

So I have been asked to read up on mocking and BDD for our development team and play around with mocks so as to improve a handful of our existing unit tests (as an experiment).
I have ultimately chosen to go with Mockito for a number of reasons (some outside the scope of my control), but namely because it supports both stubbing and mocking for instances when mocking would not be appropriate.
I have spent all day learning about Mockito, mocking (in general) and BDD. And now I am ready to dig in and start augmenting our unit tests.
So we have a class called WebAdaptor that has a run() method:
public class WebAdaptor {
private Subscriber subscriber;
public void run() {
subscriber = new Subscriber();
subscriber.init();
}
}
Please note: I do not have a way to modify this code (for reasons outside the scope of this question!). Thus I do not have the ability to add a setter method for Subscriber, and thus it can be thought of as an unreachable "blackbox" inside of my WebAdaptor.
I want to write a unit test which incorporates a Mockito mock, and uses that mock to verify that executing WebAdaptor::run() causes Subscriber::init() to be called.
So here's what I've got so far (inside WebAdaptorUnitTest):
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
When I run this test, the actual Subscriber::init() method gets executed (I can tell from the console output and seeing files being generated on my local system), not the mockSubscriber, which shouldn't do (or return) anything.
I have checked and re-checked: init is public, is neither static or final, and it returns void. According to the docs, Mockito should have no problem mocking this object.
So it got me thinking: do I need to explictly associate the mockSubscriber with the adaptor? If this is a case, then ordinarily, the following would normally fix it:
adaptor.setSubscriber(mockSubscriber);
But since I cannot add any such setter (please read my note above), I'm at a loss as to how I could force such an association. So, several very-closely-related questions:
Can anyone confirm that I've set the test up correctly (using the Mockito API)?
Is my suspicion about the missing setter correct? (Do I need to associate these objects via a setter?)
If my above suspicion is true, and I can't modify WebAdaptor, are there any circumventions at my dispose?
Thanks in advance!
You need to inject the mock into the class which you are testing. You do not need access to Subscriber. The way mockito and other mocking frameworks help is that you do not need access to objects which you are interacting with. You do however need a way to get mock objects into the class you are testing.
public class WebAdaptor {
public WebAdaptor(Subscriber subscriber) { /* Added a new constructor */
this.subscriber = subscriber;
}
private Subscriber subscriber;
public void run() {
subscriber.init();
}
}
Now you can verify your interactions on the mock, rather than on the real object.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor(mockSubscriber); // Use the new constructor
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
If adding the Subscriber to the constructor is not the correct approach, you could also consider using a factory to allow WebAdaptor to instantiate new Subscriber objects from a factory which you control. You could then mock the factory to provider mock Subscribers.
If you don't want to change the production code and still be able to mock the functionality of the Subscriber class you should have a look at PowerMock. It works fine together with Mockito and allows you to mock the creation of new objects.
Subscriber mockSubscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(mockSubscriber);
Further details are explained in the documentation for the PowerMock framework.
There is a way to inject your mock into the class under test without making any modifications to the code. This can be done using the Mockito WhiteBox. This is a very good feature that can be used to inject the dependencies of your Class Under Test from your tests. Following is a simple example on how it works,
#Mock
Subscriber mockSubscriber;
WebAdaptor cut = new WebAdaptor();
#Before
public void setup(){
//sets the internal state of the field in the class under test even if it is private
MockitoAnnotations.initMocks(this);
//Now the whitebox functionality injects the dependent object - mockSubscriber
//into the object which depends on it - cut
Whitebox.setInternalState(cut, "subscriber", mockSubscriber);
}
#Test
public void runShouldInvokeSubscriberInit() {
cut.run();
verify(mockSubscriber).init();
}
Hope this helps :-)
You could have used PowerMock to mock the constructor call without changing the original code:
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebAdaptor.class)
public class WebAdaptorTest {
#Test
public void testRunCallsSubscriberInit() {
final Subscriber subscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(subscriber);
new WebAdaptor().run();
verify(subscriber).init();
}
}
You cannot mock the Subscriber using Mockito in your current implementation.
The problem you have is that the Subscriber is constructed and then immediately accessed, Mockito has no ability to replace (or spy) the Subscriber instance after creation but before the init method is called.
public void run() {
subscriber = new Subscriber();
// Mockito would need to jump in here
subscriber.init();
}
David V's answer solves this by adding the Subscriber to the constructor. An alternative that retains the hidden Subscriber construction would be to instantiate the Subscriber in a WebAdapter no-arg constructor and then use reflection to replace that instance before calling the run method.
Your WebAdapter would look like this,
public class WebAdaptor {
private Subscriber subscriber;
public WebAdaptor() {
subscriber = new Subscriber();
}
public void run() {
subscriber.init();
}
}
And you could use ReflectionTestUtils from Springframework's test module to inject dependencies into that private field.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
ReflectionTestUtils.setField( adaptor "subscriber", mockSubscriber );
// When
adaptor.run(); // This will call mockSubscriber.init()
// Then
verify(mockSubscriber).init();
}
ReflectionTestUtils is really just a wrapper about Java's reflection, the same could be achieved manually (and much more verbosely) without the Spring dependency.
Mockito's WhiteBox (as Bala suggests) would work here in place of ReflectionTestUtils, it is contained within Mockito's internal package so I shy away from it, YMMV.

Categories

Resources