JUnit5 mocking a class inside mocked class - java

I have a following situation :
Class A (test)
.
-> Autowired B
.
-> Autowired C
A.method {
b.method2();
}
B.method2 {
c.method3();
}
Now I have to test A.method() ->
#InjectsMock
A a;
#Mock
B b;
a.method();
when b.method2() is called, it obviously doesn't do anything but I actually want it to go inside b.method2() to eventually call c.method3(). Now c.method3() is what I'd want to use Mockito.when(c.method3()).return(1);
Is this possible? If so, how do I achieve this?

When using unit testing, you should think that the only piece of software that is running is this method. The objective is to isolate a part to analyze the behavior.
To test any class, a developer must make sure that the class's dependencies will not interfere with his unit tests.
Think about this situation: you call a real b.method2 and it throws an exception you don't expect. How to evaluate this case if your objective was to test this a.method?
Unit tests verify the behavior of the units. Think of a class as being a unit. Classes most often have external dependencies. Tests for such classes should not use their actual dependencies because if the dependencies are faulty, the tests will fail, even though the code inside the class may be perfectly fine.

Related

Java and JUnit, find missing #Test decorators

Let's say we have a project full of unit tests (thousands) and they all should look like this
#Test
public void testExceptionInBla() {
// some test
}
But in one case someone forgot to put an #Test decorator on top of the test.
What would be an easy way to spot those tests, without looking through all the code manually?
I want to find code like this, it's a test without #Test:
public void testExceptionInBla() {
// some test
}
I were you I would look at some Sonnar rule here I found something that may can match requirement:
https://rules.sonarsource.com/java/RSPEC-2187
But in one case someone forgot to put an #Test decorator on top of the
test.
And
I want to find code like this, it's a test without #Test:
public void testExceptionInBla() { // some test }
Annotating the method with #Test or specifying a test prefix in the method name is about the same thing in terms of consequences if the developer forgets to do that.
If the #Test is the way today, that is not chance.
The #Test annotation brings two real advantages on the test prefix :
1) it is checked at compile test. For example #Tast will provoke a compilation error while tastWhen...() will not.
2) #Test makes the test method name more straight readable : it allows to focus on the scenario with a functional language.
should_throw_exception_if_blabla() sounds more meaningful than test_should_throw_exception_if_blabla().
About your issue : how to ensure that tests are effectively executed, I would take things in another way. Generally you want to ensure that unit tests execution covers a minimum level of the application source code (while you can go down at package or class level if makes sense).
And that is the coverage tools goal (Jacoco for example) to do that job.
You can even add rules to make the build fail if the level of coverage of classes belonging to some package are not covered at least at a specified minimum level (look at that post).
Small Adding :
If you really ensure that methods of test are correctly annotated, you have a way :
1) you have to choose a convention for test methods : for example all instance and not private methods in a test class are test methods.
2) Create a Sonar rule that retrieves all non private instance methods of test classes and ensure that all these methods are annotated with #Test.
3) Add that rule to your Sonar rules.

Mocking a dependent class using Mockito in JAVA

I am quite new to Mockito. I apologise if my question sounds sill. I have a standalone JAVA application for which I have to write Unit test cases using JUnit and Mockito. The important thing is that I cannot change the code as it has been written by someone else and Integration testing has been completed. I have tried to search for similar questions, but couldnt find anything. Solutions suggested in somewhat similar questions, didnt work :(
I have attached the flow control diagram.I want to mock the dependent classes. For example when I am Unit testing 'Class 1 --> Method 1', I want to mock the output of 'Method 2 in Class 2' WITHOUT CALLING it. I have tried to use Mockito.when and Mockito.doReturn. Both call the dependent methods.
Can someone please suggest me some ideas to achieve this ?
//Pseudocode of Class 1
public class Class1 {
public boolean method1() {
Class2 c2 = new Class2();
boolean b1 = c2.method2();
}
}
//Pseudocode of Class 2
public class Class2 {
public boolean method2() {
Class3 c3 = new Class3();
boolean b2 = c3.method3();
}
}
... Likewise same for Class 3, 4 and 5
What you're being asked to do is write unit tests for logic which was written by someone who knows absolutely nothing about writing code for test-ability. Probably a developer who's been writing code for a very long time, does things in an "old school" way and thinks he's way too important to write unit tests. Whoever wrote the logic you're testing needs to go back to school and learn some new tricks.
Anyway that doesn't help you, so you can still unit test this logic, it's just more of a pain. Mockito alone can't do it, you need "PowerMockito" which will let you mock the construction of Class2.
First things first you need to add 2 new test dependencies to your project "powermock-api-mockito"+"powermock-module-junit4".
A test class for you case would look something like:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Class1.class)
public class Class1Test {
private Class1 testSubject;
#Mock
private Class2 class2;
#Test
public void testMethod1() throws Exception {
testSubject.method1();
verify(class2).method2();
}
#Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.whenNew(Class2.class).withNoArguments().thenReturn(class2);
testSubject = new Class1();
}
}
So as you can see PowerMockito lets you mock out construction on new Class2 instances by using PowerMockito.whenNew(), this will only work if you've "prepared" Class1 using the annotation #PrepareForTest(Class1.class) otherwise Class1 can't be injected with the mock Class2 instance. Hopefully that points you in the right direction? On a side note, if you're a junior developer being asked to write unit tests for a more senior developer get out now, your development team is rotten!
Sometimes, code is not written to be testable.
Especially calling constructors inside methods or other constructors is a big issue for unit testing and mocking.
If you do not use factories or dependency inversion / dependency injection in any way, you will have a very hard time testing the code. This is one of the reasons why CDI is so popular.
Anyways, being asked to write Unit Tests after Integration Tests are already in place is kind of a bad smell. You should have written the unit tests first. If you follow Test Driven Development (TDD), you should have written your test even before you actually wrote your class. This way, it would be impossible to write classes that are hard to test.
But what to do on your already messed up situation?
I recommend to refactor your code. Instead of calling a constructor inside your methods, pass an instance into your method, or provide a field in the class in order to be able to mock it.
Reconsider the scope of your unit test. It should only test a single class. Everything else, all the dependencies should be mocked.

Mocking constructor using powermock on the class which needs to be tested

I am able to mock a constructor call using powermock from inside a class which I want to test. This works when I add the class I want to test in #PrepareForTest. But once I add my class there, even when the test cases pass, the coverage is being shown as 0 in the coverage plugin.
When I remove my class from #PrepareForTest, of course, coverage starts showing up for other test cases but the test case in which I have to mock constructor call fails. Not sure what to do about this.
Class A
{
MyObject o;
A(){
//some other code
o = new MyObject();
//some other code
}
public void process(){
//some code
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
Class TestA{
#Test
public void test1()
{
MyObject mocked = Mockito.mock(MyObject.class);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(mocked);
A a = new A();
a.process();
//Assert as per test case
}
}
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
Coverage tools rely on manipulating the executed byte code.
So does PowerMock, when you mock static/new.
This can quickly lead to all sorts of problems. For JaCoCo, there seems to be a solution around offline instrumentation. Where, I also remember: some other person asked about that some time back, and in the end gave up, because he couldn't get "offline instrumentation" to work either.
For any other framework, I have to repeat old advice: consider to invest your time to learn how to write easy-to-test code. Because if you would do that, you would not need to use PowerMock(ito) in order to test it.
Your code is hard-to-test because of that new() statement in the constructor. Simply don't do that. Either use dependency injection via #InjectMocks, or have a test-only constructor that takes the required object.
Long story sort: when you write your own, new code, and you think you need PowerMock to test it, then you are doing something wrong.
I think you can do without Powermock here. If you Spy on class A and mock the getter you should end up with the same result and most likely have your coverage correct:
#Test
public void test1(){
MyObject mocked = Mockito.mock(MyObject.class);
A spyA = Mockito.spy(new A());
doReturn(mocked).when(spyA).getMyObject();
...
}

how to unit test methods with dependencies

I need to create some unit testing for my application but I am not sure how to proceed and I couldn't find anything of help online. What I want to know is how to test an app where there are many methods dependent on a few others.
e.g.
public class foo(){
public void doIt() {
boz();
bar();
biz.baz(); //from another class
}
public void bar(){
...
}
public int boz(){
...
}
}
so in a scenario like the one presented above one would think that unit testing the doIt method would be sufficient since it is going to fail anyway if something is wrong with the methods called inside it.
Although, I am not sure if we can consider this to be unit testing as this tests the functionality of more than just an entity. In addition, if the test on the doIt method fails it is going to be really hard to tell where the error occurred especially in a case with many dependencies - doesn't that defy the meaning of unit testing?
So far the only approach I have thought is to start by testing the dependencies first (i.e. bar boz baz) and then the doIt method. That way, if the test suite gets to doIt with no errors and fails means that there is something wrong with the code implemented inside that method and not inside its dependencies.
BUT, is this the right way of doing it?
To test doIt() method without having to invoke the real implementations of bar() and baz(), use a Spy in Mockito:
Mockito spy documentation
If bar() is really void, you can do something like this:
foo f = spy(new foo());
doNothing().when(foo).bar();
Better is if you can inject your dependencies (ex: biz) as mock objects and test your foo class directly.

How to avoid SpringJUnit4ClassRunner initializing beans before them being mocked with JMockit?

I have a JUnit test class like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( locations = { "beanDefinitions.xml"})
public class MyTest {
#Mocked private SomeDependency usedInSpringContext;
#Test public void letsTest() {
...
}
}
The problem is, Spring runner loads its beans before JMockit gets a chance to mock them. How to avoid it? This is JMockit 1.0 and Spring 3.07. I'd rather had my beanDefinitions.xml unchanged.
The code under test is legacy. It contains lots of hardcoded spring dependencies I cannot get rid of easily. Thus the first step - mocking.
You can use a custom FactoryBean.
It is explained in this blog. And here is the example code.
It uses either easymock or Mockito. But I am sure you can easily port that to JMockit.
EDIT: I overlooked that you don't want your beanDefinitions.xml to be modified. But my suggestion includes that modification.
One of the great things about Spring, and dependency injection in general, is that your classes don't get cluttered up with code to satisfy thier dependencies. They just sit and wait for someone else to fill in collaborating objects. So it is supposed to be trivial to plug in mock objects.
// no Spring runner or context configuration
public class FooTest {
Foo foo;
#Before
public void setup() {
foo = new Foo();
foo.setDependency(mock(dependency)); // details depend on mocking framework
}
}
With this approach you don't autowire or otherwise inject the object you're testing, at least not if you intend to reconfigure it by pointing it at mock collaborators. If the code under test has lots of dependencies, you can wind up with a ton of setup code, but that's normal.
Admittedly, some things (like databases) are hard to mock, so you need a different testing approach to verify that your SQL queries (for example) do what you meant. This starts with a separate bean definitions file containing something like:
<jdbc:embeded-database id="datasource"/>
See http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html for more information.
The tricky part is that if you haven't been writing Junit tests all along, your may have gotten into a situation where every bean seems to depend on every other bean. So the "unit" you're trying to test isn't one class, but an bunch of interrelated classes. In that case I suggest breaking the bean definitions file into smaller parts, then write unit tests for each part.
With that approach you can let Spring wire up the code under test, because the Spring configuration is part of the unit. The unit test code still mocks and plugs in the dependencies external to that unit.
If you insist on using your real beanDefinitions.xml file in its entirety, you're writing integration tests, not unit tests.

Categories