Keeping unit tests isolated in Java - java

I'm just getting started with Java, and I'm confused about how to unit test Java classes while still keeping everything isolated. Specifically, I'm wondering how I might test a method like createProgram in this example:
package com.example.app;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import com.example.data_models.Program;
public class ProgramCreator {
private PersistenceManagerFactory pm_factory;
public ProgramCreator(PersistenceManagerFactory pm_factory) {
this.pm_factory = pm_factory;
}
public void createProgram(String name, String instructor, double price) {
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(new Program(name, instructor, price));
} finally {
pm.close();
}
}
private PersistenceManager getPersistenceManager()
{
return this.pm_factory.getPersistenceManager();
}
}
I'm pretty sure I can mock out the persistence manager factory using a library like mockito and use that to test that the makePersistent method is getting called with the right arguments, but how do I check that the fields of the program data model are correct while still keeping everything isolated? I don't want to rely on the program object's getter methods, as that would result in my unit tests for ProgramCreator being reliant on the Program class being correct. What do I do in this situation? (With Ruby, I'd probably just stub out the new method of the Program class. Is something like that possible in Java?)

By creating an object (Program) in createProgram method you are creating tight coupling between the objects. Instead delegate the work of creation to a factory and you can mock the factory in your unit test. This would mean we would be testing only what createProgram method is doing and nothing else. Trying to unit test code could give us indications to re-design/re-factor the code.
public class ProgramCreator {
private PersistenceManagerFactory pm_factory;
private ProgramFactory p_factory;
public ProgramCreator(PersistenceManagerFactory pm_factory, ProgramFactory pFactory) {
this.pm_factory = pm_factory;
this.p_factory = pFactory;
}
public void createProgram(String name, String instructor, double price) {
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(p_Factory.createProgram(name, instructor, price));
} finally {
pm.close();
}
}
}

A unit in is not necessarily limited to a single class, it is the smallest set of classes that work together. So there is nothing wrong with using the getters from Program while testing ProgramCreator.

You don't have to test everything, everywhere.
Do as you say: mock the appropriate code to test createProgram and see if the results of that are as you expect them to be (aka: there has been a program persisted with the given fields).
You don't have to necessarily test that you actually create a new Program that has those fields. You could just as well test in a different method whether or not new Program(name, instructor, price) creates a new object with the right values.
The most important part about unit tests is this flow:
-> General idea
-> Logic performed
-> End situation reached
Your situation fills this in as
-> I want to test createProgram with variables X, Y and Z
-> ??
-> The database should return a program that has values X, Y and Z
All together you don't really care what happens in the second step, as long as the end result works. For this reason you can allow more general tests in your code that basically perform logic and check if the result of all that equals your desired output.
The obvious issue with this is ofcourse: in the case of an error, won't this mean I have to manually debug to find the issue? Yes, it does. That's why you should add many smaller tests (like testing the constructor) to help pinpoint the exact issue.
There certainly is nothing wrong with using getters and setters. In fact, you will most certainly need them. It's about testing workflow, not necessarily testing isolated methods.

Related

Change the value for each test method before #Before annotation is called in JUnit

I am writing a test for a class which has a setup
class A
{
private String name;
public String getName()
{
return "Hello "+ name;
}
public void setName(String name)
{
this.name = name;
}
My test class
TestA
A a = new A();
{
#Before
void setup()
{
a.setName("Jack");
}
#Test
public void testTom()
{
assert(a.getString(), "Hello Tom");
}
#Test
public void testJack()
{
assert(a.getString(), "Hello Jack");
}
How to change the value of name between the methods since #Before calls for every test method?
ie) if execute testJack then the output should be Hello Jack.
I tried with #Parameters but before that setup is getting called so i couln't acheive this functionality.
First, the code:
#Before
void setup()
{
A a = new A();
a.setName("Jack");
}
Doesn't do anything which the Tests can see. You're creating a local variable a which goes out of scope almost immediately.
#Before is designed to set and reset a state or context before each Test is run. It doesn't vary unless something it relies on changes between invocations.
You could create a Stack as an instance variable and pre-populate it in a #BeforeClass method, and have #Before pop a value to be used every time it's called. This is unadvisable as it assumes that the Tests will be run in some particular order. It's much cleaner and clearer to just declare different values inside each Test.
There is simply no point in doing that; as your real problem is rooted in your statement "Just assume the scenario of 30 lines of code in setup".
If you need 30 lines of setup code, then your code under test is not following the "single responsibility principle" and doing way too many different things.
Of course, you can turn to "data driven" testing to somehow get there (see here for example); but that would be fixing the Y side of an XY problem.
I know, it sounds harsh: but you better step back; and learn about doing reasonable OO design (for example based on SOLID). Then you rework your code to not need 30 lines of setup code.
You see, if your code is so hard to test; I guarantee you: it is also hard to understand, and will be close to impossible to maintain/enhance over time. And beyond that: it will be even hard to get your code to be "correct" in the first place.
Long story short: have a look in these videos and improve your design skills.

How to stub return value for the private method of same class using mockito

I am working on spring based project and writing unit test case using JUnit + Mockito. I am facing a problem while stubbing boolean value to a private method of same test class (after changing access level to public, still I have failed to stub the boolean value).
Below code snippet shows the simulation of same problem
class ABC {
public String method1(User userObj){
String result = "";
if(!isValidUser(userObj.getSessionID())){
return "InvalidUser";
} else {
// execute some logic
}
return result;
}
private boolean isValidUser(String sessionId) {
// Here it calls some other class to validate the user
if (sessionId == null || UserSessionPool.getInstance().getSessionUser(sessionId) == null) {
return false;
} else {
return true;
}
}
}
Here, I would like to write a test case for method1(). In class ABC I have a method called isValidUser() which helps to identify the user with in a session by looking into a global session pool which holds all logged-in used details i.e. UserSessionPool.getInstance().getSessionUser(sessionId).
While testing method1(), the moment test controller triggers isValidUser(userObj.getSessionID()) I would like to return true from isValidUser() method, so that I can continue to test rest of the implementation logic.
So far I have tried following ways using spy and mocked object to call the isValidUser() method and try to return true but nothing worked well.
Using PowerMockito
PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);
or
PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());
Using Whitebox
Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());
Using Mockito.when
when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);
or
Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());
The other answer is: fix your design instead of turning to the big PowerMock hammer.
Yes, PowerMock allows you to mock static methods. But you should understand: static is an abnormality in good OO design. You only use it when you have very good reasons. As it leads to tight coupling between your classes, and surprise: it breaks your ability to write reasonable unit tests. Yes, PowerMock works; but sometimes, it does not. When your classes grow, and you do more and more things "statically", because, you know, PowerMock will do the job ... be prepared for bizarre fails at some point, that can take hours to hunt down; without ever finding real bugs in your production code.
So, consider an alternative:
Do not use static method calls. And if there is some static method around that you can't touch; consider building a small interface around that.
Instead: use dependency injection and simply pass objects implementing some interface into your production code. Because you can mock such objects without the need for PowerMock(ito).
In that sense: you simply created hard to test code. Now you intend to fix that using PowerMock. The other way (much more reasonable in my eyes) is to learn how to write testable code in the first place. Here is a good starting point for that.
Can you please try this out.
#Before
public void setUp() {
UserSessionPool mockConnectionPool = Mockito.mock(UserSessionPool.class);
}
#Test
public void testName() throws Exception {
//given
PowerMockito.mockStatic(UserSessionPool.class);
BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool);
Mockito.when(mockConnectionPool.getSessionUser(Mockito.anylong())).thenReturn(something);
//then
PowerMockito.verifyStatic();
}
Hope this helps. Happy coding !

How to test java reflections code using JUnit

I have a java class that invoke a method via reflection. That method create database connection and perform database operations. i want to test my reflections code using junit. Is there any way to do that?
Please find my code snippet below.
Class DaoImpl {
public void setResult(String result) {
this.result = result
}
public String getResult() {
return this.result;
}
public void doDBoperation() {
Connection connection = getConnection();
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("Select column_name from table");
if(rs.next()) {
result = "value";
}
}
}
Class ReflectionClass {
public void invoke() {
Class<?> noParam = {};
Class<?> clazz = Class.forname("DaoImpl");
Method method = clazz.getDeclaredMethod("doDBoperation", noParam);
method.invoke(clazz.getNewInstance);
System.out.println("This is it");
}
}
How to write JUnit test case for my ReflectionClass?
As #GhostCat suggested PowerMockito could be used to try to mock DaoImpl's constructor. Here's the code:
import org.junit.Test;
import org.junit.runner.RunWith;
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(ReflectionClass.class)
public class ReflectionClassTest {
#Test
public void invoke() throws Exception {
DaoImpl mockedDaoImpl = PowerMockito.mock(DaoImpl.class);
PowerMockito.whenNew(DaoImpl.class).withNoArguments().thenReturn(mockedDaoImpl);
new ReflectionClass().invoke();
Mockito.verify(mockedDaoImpl, Mockito.atLeastOnce()).doDBoperation();
}
}
But, it doesn't work. PowerMock doesn't manage to mock the constructor when invoked through reflection.
There is no real "pure unit test" way of testing *ReflectionClass**. Normally, you would do a unit test by providing a mocked instance of that class to your production code; then you could use the mocking framework to verify that the expected method was called.
But in your case, you created code that is simply hard to test (if you want to learn how to address that part, you might want to watch these videos). You are basically calling "new" directly in your production code; thus there is no way to insert a mocked object. And beyond that, you also can't mock those reflection methods.
The only option to maybe get this code tested would be to use Mokito together with PowerMock. But I am not an expert in that area, and can't promise you that it will work.
My recommendation to you: step back first and figure if you can get away from using reflection, or at least: to separate concerns here. Because as said: your production design looks weird; and instead of spending hours to get that somehow unit tested; you should rather spent a fraction of that time to improve your design! "Hard to test" typically means "design could be improved"!
Meaning: first you create an interface that denotes the function that you want to test. Then you separate your production code of ReflctionClass, like:
One part is responsible for providing an instance of that interface (and that code could be using reflection to do its job, if that is really required)
The other part then calls the method(s) you want to be called on that interface object.
By doing so, you get two parts that you can test independently of each other!
Edit: what I mean by "bad design" - why are you using reflection to do both - object creation and method invocation? You see, you could simply cast that created object to its correct class (at least if you have an interface defined there) and then do a ordinary method call on that typed object.

How to write unit test by mocking, when you have zero arg:constructors

I was trying to write unit test using jmocks and junit. (My Project uses core java- no frameworks-) I could not write unit test for some of my classes, by mocking external dependencies, when dependencies were initialized in a a no arg-constructor.
As i cannot provide the actual code, trying to explain the scenario by an example
public interface Apple {
String variety();
}
Implementation.
public class MalgovaApple implements Apple {
#Override
public String variety() {
return "Malgova";
}
}
Class to be tested
public class VarietyChecker {
private Apple apple;
VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}
public String printAppleVariety(){
String variety = apple.variety();
if(variety.length() < 3){
System.out.println("Donot use Code names- Use complete names");
return "bad";
}
return "good";
}
}
Junit test using jmock
public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test_VarietyChecker() throws Exception{
final Apple mockapple = context.mock(Apple.class);
VarietyChecker printer = new VarietyChecker();
context.checking(new Expectations(){{
oneOf(mockapple).variety();will(returnValue("as"));
}});
String varietyNameValid = printer.printAppleVariety();
assertEquals("bad",varietyNameValid);
} }
This test fails - Mocking does not work the values "as" is not injected, the test class executes with MalgovaApple ...
Now if we add below constructor to VarietyChecker and use it test case - it gives expected output...
public VarietyChecker(Apple apple) {
super();
this.apple = apple;
}
and in unit test create test class object like
VarietyChecker printer = new VarietyChecker(mockapple);
Exposing a new constructor just for the purpose of testing is not a good idea. After all it is said that you should not alter the code for testing alone, more than that, i am afraid we have already written "some"(amount) code...
Am i missing something in junit or jmock that can make mocking work even incase of no-arg constructors. Or is this a limitation of simple junit and jmocks and should i migrate to something powerful like Jmockit /PowerMock
You should consider two choices.
Use a constructor parameter as you describe.
In this case, you're not "exposing a new constructor just for the purpose of testing". You're making your class more flexible by allowing callers to use a different factory implementation.
Don't mock it.
In this case, you are declaring that it never makes sense to use a different factory. Sometimes this is okay. At that point, the question changes, though. Instead of, "How do I mock this?" your question is now, "What am I gaining from writing this test?" You might not be gaining much of anything, and it might not make much sense to write the test at all.
If you don't mock it and decide a unit test is still worth it, then you should be asserting on other aspects of the code. Either an end state or some output. In this case, the factory call becomes an implementation detail that's not appropriate for mocking.
It's important not to fall for a "unit test everything" mentality. That is a recipe for Test-induced Design Damage. Evaluate your tests on a case by case basis, deciding whether they're providing you any real value or not. Not writing a unit test is a valid option and is even appropriate at times, even if it's option you try very hard to avoid.
Only you can make a determination which one makes the most sense in this case. From the the fact that this is a factory object we're talking about, I'd probably lean toward the former.

JUNIT Conditional Tests possible?

I have a series of data each one containing info_A and info_B. I would like to:
if(info_A) {
run Test A
} else if(!info_A) {
run Test B
}
It is very important that only the Test actually run is shown in the JUnit GUI tree. How can I do this?
The following solutions do not work:
If I use the Assume.assumeTrue(conditon), I can Ignore a test but then it is still displayed as passed in the test.
Doing this:
Result result = JUnitCore.runClasses(TestStep1.class);
leads to the correct result but the JUnit tree is not built.
Using #Catagories also shows the failed tests, which is also what I don't want.
You can use Assume to turn tests on/off conditionally:
A set of methods useful for stating assumptions about the conditions in which a test is meaningful. A failed assumption does not mean the code is broken, but that the test provides no useful information.
You can do this with JUnit Rules.
There's a whole blog post dedicated to exactly your question here, but in short, you do the following:
Create a class that implements the org.junit.rules.TestRule interface. This interface contains the following method:
Statement apply(Statement base, Description description);
The base argument is actually your test, which you run by calling base.execute() -- well, the apply() method actually returns a Statement anonymous instance that will do that. In your anonymous Statement instance, you'll add the logic to determine whether or not the test should be run. See below for an example of a TestRule implementation that doesn't do anything except execute your test -- and yes, it's not particularly straighforward.
Once you've created your TestRule implementation, then you need to add the following lines to to your JUnit Test Class:
#Rule
public MyTestRuleImpl conditionalTests;
Remember, the field must be public.
And that's it. Good luck -- as I said, you may have to hack a little, but I believe there's a fair amount explained in the blog post. Otherwise, there should be other information on the internets (or in the JUnit sourc code).
Here's a quick example of a TestRule implementation that doesn't do anything.
public abstract class SimpleRule implements TestRule {
public Statement apply(final Statement base, final Description description) {
return new Statement() {
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable t) {
t.printStackTrace();
}
}
};
}
}

Categories