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.
Related
I see a couple different ways of mocking objects. What exactly are the differences between this approache using InjectMocks and the approach shown here: https://github.com/mockito/mockito/wiki/Mocking-Object-Creation?
#ExtendWith(MockitoExtension.class)
public class MyTest() {
#Mock ClassB uut;
#InjectMocks ClassA cA;
#Test
public TestOne() {
...
}
}
where
public class ClassA() {
public ClassA() {
ClassB temp = new ClassB();
}
}
versus the method shown here:
https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
What exactly is the difference?
I believe there is no essential difference between those approaches.
InjectMocks approach
Actually for it to work, your class should accept the dependencies through the constructor or setters (and it never works with both). I would say that this approach makes the testing easier because you inject whatever you want to your class object at the initialization phase.
class Foo {
private final Bar bar;
public Foo(final Bar bar) {
this.bar = bar;
}
}
If this is our class under test, then all #InjectMock does is to create mocks, and do the following:
Foo foo = new Foo(barMock);
Apart from being testable, imagine if the Bar is an interface, then you can possibly you can switch between multiple implementations of it without actually touching the class code (ideally). If you have a DI framework, that's even easier. So, basically this format of the class makes it flexible.
Using one-line methods for object creation
Let's say this is our class under test. As you can see, I am initializing the property inside the constructor. Legally, with no reflection magic, I cannot put a mock bar variable neither during initialization nor after that.
class Foo {
private final Bar bar;
public Foo() {
this.bar = new Bar();
}
}
The reason that Mockito docs tell you to switch to either a one-liner method or a Factory helper is that:
Mockito cannot mock constructors, which means you cannot put a mock object in the place of bar without reflection, and you can only do that after the initialization. Generally, to point of my view on testing, reflection should be avoided as much as possible.
One-liner functions are looking as clean as constructors and they can be descriptive (like static factory methods).
So, when you switch your class to look like this:
class Foo {
private final Bar bar;
public Foo() {
this.bar = makeBar();
}
Bar makeBar() {
return new Bar();
}
}
Now, you can put a spy, and just mock the makeBar method easily. The same applies to the factory method as well. To be honest, the factory approach looks a bit wordy to me, but still, I am sure there will be times when it may come handy.
I have a enum that has to have a inner static class for bean injection.
I feel I'm facing the most difficult situation for a mock: enum, static class, static field, static method..
public enum Category{
C1(Something(Constants.getFactory().createSomething(""))),
C2(...);
public static Constants {
#Autowired
private static Factory factory;
public static Factory getFactory(){
return factory;
}
}
}
And my testing class using PowerMockito is:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Category.class,Category.Constants.class})
public class CategoryTests {
#Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Category.class);
PowerMockito.mockStatic(Category.Constants.class);
//This simply testing mock didn't work
//PowerMockito.when(Category.Constants
// .getFactory()).thenReturn("123");
//I tried to mock the inner field 'factory' and use it directly without a getter
//(with small changes in the original class)
//But it didn't work either
Factory factory = PowerMockito.mock(Factory.class);
NewClass newClass = PowerMockito.mock(NewClass.class);
PowerMockito.when(Factory.createSomething(anySring()))
.thenReturn(newClass);
Whitebox.setInternalState(
Category.Constants.class,"factory",Factory);
//This is like the most common way to stub
//It didn't work, so I believe the inner static class were never mocked
PowerMockito.doReturn(factory).when(Category.Constants.class,
"getFactory", anyString());
}
//I don't know if real test cases matter that much but I update to add it for reference.
#Test(dataProvider = "Case1")
public void testFromFilterType(final String testName, String input, final Category expected) {
assertEquals(Category.doSomething(input), expected);
}
#DataProvider(name = "Case1")
Object[][] fromFilterTypeCases() {
return new Object[][] {
{ "C1", "input1", Category.C1 },
{ "C2", "input2", Category.C2 },
};
}
}
//Currently the tests got skipped because in class Category Constants.getFactory().createSomething(""),
//where Constants.getFactory() returns null and mocking doesn't work.
At first I didn't mock the Enum, but just the static inner class. After heavily searching, I tried in all ways. The setup seems correct but it may miss some tricks. Any helps?
A bit of guessing: Category.class is the class you intend to test. That class itself contains nothing that should require mocking/preparation.
So: drop these parts in your code. Even if it doesn't cause your current issue, I am pretty sure that it might have all kinds of unwanted consequences when you start testing things later on.
Beyond that, the real answer would be to avoid the necessity for PowerMock(ito) in the very first place. You are already using #Autowired, which implies that you are using a DI framework. Most DI frameworks also have hooks for unit testing. So you should rather try to get #Autowired to work in your test setup.
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.
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;
}
}
I was wondering whether there's a way to mock the field which is being autowired.
Consider the following case.
I have a class name A
public class A {
#Autowired
private B b;
public void aMethod() {
b.method();
}
}
The other class B looks like this
public class B {
public void method() {
// some code
}
}
Now i want to write junit for the method.
I know there's a way to mock the autowired field like this.
public class TestA {
#InjectMock
private A a;
#Mock
private B b;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
public void testAMethod() {
// write test case.
}
}
But my question is -> Is there a way to mock the autowired field inside method after creating object with new.
eg
public class TestA {
public void testAMethod() {
A a =new A();
// how to mock the B instance in it.
}
}
Please suggest or there's no way to do this????
I dont want to change from private modifier. Nor i want to add getter's and setters or reflection. I just want to know is there a way to mock the B instance after creating the new object of A class.
How about ReflectionTestUtils?
A a = new A();
B b = mock(B.class);
ReflectionTestUtils.setField(a, "b", b);
It's still reflection-based and has all related drawbacks, though it's quite simple and easy to read.
You can not do that with mockito, this would require to modify the bytecode of the class being tested. However Powermock allows such stubs. Note though that I and the creator of Powermock - Johan Haleby - would push for a refactoring instead of using Powermock. Powermock is very powerful, maybe too much, and working allows anyone to write legacy code, that would be difficultly maintainable or extensible (property you can find in poorly designed legacy code).
In your case I don't know what's wrong in your case with the dependency injection. However if the code need a new instance of B, it may be useful to have inject in A a factory/provider/builder class which will make a new instance of B. Such code can be easily stubbed with Mockito.