How to design a class for unit tests - java

I have a Java class like the following:
public class MyClass {
/** Database Connection. */
private dbCon;
public MyClass() {
dbCon = ...
}
public void doSomethingWith(MyData data) {
data = convertData(data);
dbCon.storeData(data);
}
private MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
since the true logic of this class lies in the convertData() method, I want to write a Unit Test for this method.
So I read this post
How do I test a private function or a class that has private methods, fields or inner classes?
where a lot of people say that the need to test a private method is a design smell. How can it be done better?
I see 2 approaches:
Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibilty principle, unless I create a lot of utility classes with maybe only one or two methods.
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Are there any best practices regarding this problem?

Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibility principle, unless I create a lot of utility classes with maybe only one or two methods.
You interpretation of this is wrong. That is exactly what the SRP and SoC (Separation of Concerns) suggests
public interface MyDataConverter {
MyData convertData(MyData data);
}
public class MyDataConverterImplementation implements MyDataConverter {
public MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
convertData implementation can be now tested in isolation and independent of MyClass
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Wrong again. Research Explicit Dependency Principle.
public class MyClass {
private DbConnection dbCon;
private MyDataConverter converter;
public MyClass(DbConnection dbCon, MyDataConverter converter) {
this.dbCon = dbCon;
this.converter = converter;
}
public void doSomethingWith(MyData data) {
data = converter.convertData(data);
dbCon.storeData(data);
}
}
MyClass is now more honest about what it needs to perform its desired function.
It can also be unit tested in isolation with the injection of mocked dependencies.

Related

Is this the good class design practice in Java?

public class OneClass {
private AnotherClass anotherClass = new AnotherClass();
private void doOneJob(){
anotherClass.doOtherJob();
}
}
In the above code, AnotherClass is instantiated and held as a class variable of OneClass.
What are the consequences of this design?
Is it a good practice?
Will this support unit testing?
This is called composition and is a fundamental part of Java language. There is nothing wrong with it, and might be essential in a lot of cases.
The only change I would do is use dependency injection to make it easier for testing, i.e. you'll be able to supply a mock AnotherClass object this way:-
public class OneClass {
private AnotherClass anotherClass;
public OneClass(AnotherClass anotherClass){
this.anotherClass = anotherClass;
}
private void doOneJob() {
anotherClass.doOtherJob();
}
}
It is hard to "unit" testing because you cant mock the "external" dependency in a normal way. (With groovy tests for example you can override private fields with a mock)
I think it would be better that you have a constructor that accepts a AnotherClass than you can mock it in a unit test via constructor.

Unit testing a function that is calling another static function in android java using Mockito

I have a scenario where I call a static function from another function. How can we write unit tests in such cases?
Here is my code:
public class TradesHelper {
public static double calculatePL(Market market, Trade trade) {
double pl = (Helper.priceDifference(market, trade) / market.getSize()) * trade.getQuantity() * Helper.effectiveValue(market);
return pl;
}
}
public class Helper {
public static priceDifference(Market market, Trade trade) {
//Do something here
}
}
This is how I am trying to write unit test case:
I have written a unit test case for Helper class. But for TradesHelper class this is how I am trying to write:
public class TradesHelperTest {
#Mock
Market market;
#Mock
Trade trade;
#Test
public void calculatePlFromPips_Test() {
//Trying to return a value when priceDifference function in Helper class is called
Helper helper1 = spy(new Helper());
doReturn(0.0012999999999999678).when(helper1).priceDifference(new Market(),new Trade());
}
But I am getting thus error:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
I am new to writing unit tests. Can someone guide me on how to do it write?
Thanks
As the comments tell you cannot mock static methods with pure "vanilla" Mockito.
But static access is a bad design and should be avoided. You problem creating a test is the prove that static access makes the code using tightly coupled and therefor hard to reuse (since testing is kind of "reuse"...).
Static access also effectively prohibits inheritance and polymorphism, two major concepts why we are using an OO language.
On the other hand there is not rule that "helper classes" or "utility classes" (in the sense that they provide common behavior) must have static methods. This is only a misconception because classes with only static methods used to be called "utility classes".
So instead of surrendering to your bad design and using Powermock you should change both class Helper and class TradesHelper to have non static methods and use objects of them in your production code.
Java is an object oriented programming language after all, so why avoiding objects?
But do not instantiate Helper inside TradesHelper. Pass the instance of Helper in as a constructor parameter:
public class TradesHelper {
private final Helper helper;
public TradesHelper(Helper helper){
this.helper = helper;
}
public double calculatePL(Market market, Trade trade) {
// ...
public class TradesHelperTest {
#Mock
Market market;
#Mock
Trade trade;
#Mock
private Helper helper;
private TradesHelper tradesHelper; // class under test, no mock nor spy!
#Before
public void setup(){
tradesHelper= new TradeHelper(helper);
}
#Test
public void calculatePlFromPips_Test() {
// arrange
doReturn(0.0012999999999999678)
.when(helper)
.priceDifference(market,trade);// use mocks here not new objects
// act
tradesHelper.calculatePL(market,trade);
// assert
// either assertThat() or verify()
}
}

Powermock - mocking static class members

I'm trying to mock the following class which contains some static members
public class ClientFact {
private static final String BASE_URL = Config.getProperty("prop1");
private static final String USERID = Config.getProperty("prop2");
......................
public static Client createClient() throws AppException {
}
}
but i'm running into issues with the static member variables which are populated by Config.getProperty. This class does a read on a properties file like so
public class Config {
...............
public static String getProperty(Param param) {
String value = null;
if (param != null) {
value = properties.getProperty(param.toString());
}
return value;
}
}
I'm trying to mock this call since i dont care about the loaded properties in my test. This is what ive tried
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClientFact.class})
public class MyTests {
#Test
public void test() {
PowerMock.mockStaticPartial(Config.class, "getProperty");
EasyMock.expect(Config.getProperty(EasyMock.anyObject())).andReturn(EasyMock.anyString()).anyTimes();
PowerMock.mockStatic(ClientFact.class);
}
}
but its giving the following error...
java.lang.NoSuchMethodError: org/easymock/internal/MocksControl.createMock(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Ljava/lang/Object;
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2214)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
any ideas what im doign wrong here?
A non-answer: consider not making static calls there.
You see, that directly couples that one class to the implementation of that static method in some other class; for no real reason. (and for the record: it seems strange that a USER_ID String is a static field in your ClientFact class. Do you really intend that all ClientFacts are using the same USER_ID?!)
You could replace that static call with a non-static version (for example by introducing an interface); and then you can use dependency injection to make an instance of that interface available to your class under test. And then all your testing works without the need to Powermock.
Long story short: very often (but not always!) the need to turn to Powermock originates in production code which wasn't written to be testable (like in your case). Thus instead of using the big bad Powermock hammer to "fix" your testing problem, you should consider improving your production code.
You might want to listen to those videos to get a better understanding what I am talking about.

How can we test that a class implements many interfaces?

My question is about testing a class that implements many interfaces. For example, I have this class:
public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged {
}
Now there are two ways for testing. The first is testing directly on the concrete class. That means the object type is the concrete class rather than the interface.
public class ServiceControllerImplTest {
ServiceControllerImpl instance;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
// you can bring this instance anywhere
}
}
The second way is testing on the interface only. We must typecast this object to all interfaces it implements.
public class ServiceControllerImplTest {
ServiceController instance; // use interface here
IDataChanged dataChangeListener;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
dataChangeListener = (IDataChanged) instance;
// instance and dataChangeListener "look like" two different object.
}
}
I prefer the second solution because maybe in future we can change the interface it implements to other objects, so using the concrete class might lead to failing tests in the future. I don't know the best practice for this problem.
Thanks :)
I prefer second solution because in reality, maybe in future we can change the interface it implements to other objects, so force using concreted class maybe leads to fail test in the future.
I guess it will lead to failed tests anyway, because you usually test that assertions are true or false. The question is: Do that tests apply to any IDataChanged or do these assertions only apply to the ServiceControllerImpl?
If the assertions only apply to the ServiceControllerImpl it doesn't matter if you use an IDataChanged instead of an ServiceControllerImpl, because you must edit the test when you use another IDataChanged object - different assertions. The test will fail if you use another object.
The way you setup unit tests Itself gives you an answer. A unit test usually tests one class in isolation. This means that you mock the environment. But mocking the environment means that you know the dependencies of the class you test and this are implementation details. So your test is written on an implemtation basis rather than only the interface.
It's possible to write tests that only test an abstract api - like an interface. But this usually means that your tests are abstract too. E.g.
public abstract class SetTest {
#Test
public void addAlreadyExistentObject(){
Set<String> setUnderTest = createSetUnderTest();
Assert.assertTrue(setUnderTest.isEmpty());
boolean setChanged = setUnderTest.add("Hello");
Assert.assertTrue(setChanged);
setChanged = setUnderTest.add("Hello");
Assert.assertFalse(setChanged);
Assert.assertEquals(setUnderTest.size(), 1);
}
protected abstract Set<String> createSetUnderTest();
}
You can then extend these abstract tests to test the api for concrete classes. E.g.
public class HashSetTest extends SetTest {
#Override
protected Set<String> createSetUnderTest() {
return new HashSet<String>();
}
}
In this case you can replace the implementation and the test must remain green.
But here is another example of an abstract api when replacing the object under test does not really make sense.
What about writing a test for all Runnables?
public class RunnableTest {
#Test
public void run(){
Runnable runnable = ...;
// What to test here?
// run is invoked without throwing any runtime exceptions?
runnable.run();
}
}
As you can see it does not make sense in some cases to write tests in a way so that you can easily replace the object under test.
If an api like the Set api defines a concrete state handling you can write abstract tests that test this.
JayC667 already correctly answered that it's best to refer to a class through its supertype(s) in tests of methods defined by those types. But I'd change the way you did that a bit to avoid casting:
public class ServiceControllerImplTest {
ServiceController controller;
IDataChanged dataChangeListener;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
controller = instance;
dataChangeListener = instance;
}
}

How should I unit-test a long function?

If i have a long method of code which gathers data from 2 or 3 difference sources and returns a result. How can I refactor it so that it is more unit-testable? This method is a webservice and I want to make one call from client code to gather all the data.
I can refactor some portions out into smaller methods which will be more testable. But the current method will still be calling those 5 methods and will remain less testable. Assuming Java as programming language, is there a pattern for making such code testable?
This is a very common testing problem, and the most common solution I come across for this is to separate the sourcing of data from the code which uses the data using dependency injection. This not only supports good testing, but is generally a good strategy when working with external data sources (good segregation of responsibilities, isolates the integration point, promotes code reuse being some reasons for this).
The changes you need to make go something like:
For each data source, create an interface to define how data from that source is accessed, and then factor out the code which returns the data into a separate class which implements this.
Dependency inject the data source into the class containing your 'long' function.
For unit testing, inject a mock implementation of each data source.
Here is some code examples showing what this would look like - note that this code is merely illustrative of the pattern, you will need some more sensible names for things. It would be worth studying this pattern and learning more about dependency injection & mocking - two of the most powerful weapons in the unit testers armory.
Data Sources
public interface DataSourceOne {
public Data getData();
}
public class DataSourceOneImpl implements DataSourceOne {
public Data getData() {
...
return data;
}
}
public interface DataSourceTwo {
public Data getData();
}
public class DataSourceTwoImpl implements DataSourceTwo {
public Data getData() {
...
return data;
}
}
Class with Long Method
public class ClassWithLongMethod {
private DataSourceOne dataSourceOne;
private DataSourceTwo dataSourceTwo;
public ClassWithLongMethod(DataSourceOne dataSourceOne,
DataSourceTwo dataSourceTwo) {
this.dataSourceOne = dataSourceOne;
this.dataSourceTwo = dataSourceTwo;
}
public Result longMethod() {
someData = dataSourceOne.getData();
someMoreData = dataSourceTwo.getData();
...
return result;
}
}
Unit Test
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ClassWithLongMethodTest {
#Test
public void testLongMethod() {
// Create mocked data sources which return the data required by your test
DataSourceOne dataSourceOne = mock(DataSourceOne.class);
when(dataSourceOne.getData()).thenReturn(...);
DataSourceTwo dataSourceTwo = mock(DataSourceTwo.class);
when(dataSourceTwo.getData()).thenReturn(...);
// Create the object under test using the mocked data sources
ClassWithLongMethod sut = new ClassWithLongMethod(dataSourceOne,
dataSourceTwo);
// Now you can unit test the long method in isolation from it's dependencies
Result result = sut.longMethod();
// Assertions on result
...
}
}
Please forgive (and correct) any syntactic mistakes, I don't write much java these days.
The test for the "big" method will look like integration test where the smaller methods can be mocked.
If you can separate the "big" method into five isolated methods, then the "big" method could be further partitioned into semantically-/contextually-meaningful groups of the isolated methods.
Then you can mock the larger groupings of isolated methods for the "big" method.

Categories

Resources