Here is the simple class I test. It looks strange but I have oversimplified it for a reason.
public class DishService {
DaoFactory daoFactory = DaoFactory.getInstance();
public void exampleMethod() {
System.out.println(daoFactory);
DishDao dishDao = daoFactory.createDishDao();
System.out.println(dishDao.findById(1));
}
}
And here is the DaoFactory class
public abstract class DaoFactory {
private static DaoFactory daoFactory;
public abstract UserDao createUserDao();
public abstract DishDao createDishDao();
public abstract OrderDao createOrderDao();
public static DaoFactory getInstance() {
if (daoFactory == null) {
synchronized (DaoFactory.class) {
daoFactory = new JDBCDaoFactory();
}
}
return daoFactory;
}
}
And here is my test class
#ExtendWith(MockitoExtension.class)
class DishServiceTest {
#Spy
DishService dishService;
#Mock
DishDao dishDao;
#Mock
DaoFactory daoFactory;
#Test
void example() {
MockedStatic<DaoFactory> daoFactoryDummy = Mockito.mockStatic(DaoFactory.class);
daoFactoryDummy.when(DaoFactory::getInstance).thenReturn(daoFactory);
Mockito.when(daoFactory.createDishDao()).thenReturn(dishDao);
when(dishDao.findById(1)).thenReturn(new Dish());
dishService.exampleMethod();
}
The problem is that daoFactory simply is not mocked. As you can see, I return new Dish ( default constructor ), so System.out.println() should show an empty object but it connects to DB and fetch object from real daoFactory.
And here is what I see in console
Dish{name='dadawd', description='wdadwad2', category=DRINKS, price=23131.00, imageFileName='FIRSTSnacksAsDaypart_1.jpg', orderItems=null}
Unnecessary stubbings detected.
-> at service.DishServiceTest.example(DishServiceTest.java:35)
-> at service.DishServiceTest.example(DishServiceTest.java:36)
35 and 36 lines of code you can see at the screen.
At which point do you initialize/create dishService object? In the #BeforeTest?
Since you have a field daoFactory on dishService object, DaoFactory.getInstance() gets called before you mock its methods, as it is called when you create dishService object.
So you need to create dishService object after you have mocked the Factory static methods, inside #Test method.
Or another way would be to use DaoFactory.getInstance() directly in the dishService.exampleMethod().
In both cases: first mock static method, then call it.
Also don't forget to close static mock, or even better: use it inside try-with-resources construct.
Related
I'm a bit new to mocking, but I have a class (lets call it ClassA) with methods including one that returns a put response after sending an item to a database.
This class is called in another class (lets say ClassB), but classB's methods do not return the response from ClassA.
Given the following structure for ClassA and ClassB:
private final DatabaseClientFactory dbClientFactory;
private final DatabaseClient dbClient;
... other instance vars ...
public ClassA() {
ClassA(new ..params, new dbClientFactory());
}
public ClassA(...some parameters ... DatabaseClientFactory dbClientFactory) {
....
this.dbClientFactory = dbClientFactory;
this.dbClient = this.dbClientFactory.get();
}
public PutResponse methodA() {
...
dbClient.put(...);
}
and ClassB:
public ClassB(...some params..., ClassA aClass) {
}
public void methodB() {
aClass.methodA();
...more random code
}
I've tried to set up the mock equivalent to this logic:
public class classBTest {
#Mock
private ClassA aClass = new ClassA();
private ClassB bClass;
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
bClass = spy(ClassB(aClass));
#Test
public void test() throws Exception {
bClass.methodB();
when(aClass.methodA(any())).thenReturn(PutResponse.newBuilder().build());
verify(aClass, Mockito.times(1)).methodA(any());
}
I kept getting an error that
Wanted but not invoked:
aClass.methodA(<any>);
Actually, there were zero interactions with this mock.
So I tried a few things
I tried changing the constructor call of bClass to be bClass = spy(ClassB(mock(ClassA.class)))
I tried adding when(classA.methodA(any())).thenReturn(PutResponse.newBuilder().build());
to the setUp method.
I tried setting up spy on an instance of ClassA, with mocked parameters
I tried using #InjectMocks but ended up with a null pointer exception.
But now I'm stuck
Any suggestions?
*Note that ClassA has an empty constructor by default
I'm using mokito to inject a mock. This object extends a class that requires a contructor with arguments. How to mock this object that requires constructor arguments and pass this arguments as mock too?
Example class
public abstract class AbstractClassRequireContructor{
protected AbstractClassRequireContructor(Object param) {
}
public class ClassA extends AbstractClassRequireContructor{
public ClassA(Object param) {
super(param); // required by super class
}
}
Test class
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA; // requires contructor from super class
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
// how to inject mocked argument?
classA = new ClassA(paramMockToBeAddedByConstructor); // this doesn't work
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue); // use injectMock class normally
}
}
Is there any another strategy to work arroung this better?
Drop the instantiation of a new ClassA object. It should work without it as follows:
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA;
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue);
}
}
How can I mock a member class in another class which has already been spied by PowerMockito.spy()?
#Component
public class BoxFileDao {
#Autowired
private BoxFileService boxFileService;
public void uploadFile() {
.....
boxFileService.uploadFile(user, credential);
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(BoxFileDao.class)
public class BoxFileDaoTest {
#Test
public void testUploadFile() {
BoxFileDao mock = PowerMockito.spy(new BoxFileDao());
(how do I get the boxFileService from mock?)
mock.uploadFile();
verify(boxFileService).uploadFile(user, credential);
}
}
You can use #InjectMock to inject the mocked boxFileService object in the real boxFileDao object. Your test class can be written something like
#RunWith(PowerMockRunner.class)
public class BoxFileDaoTest {
#Mock
private BoxFileService boxFileService;
#InjectMocks
private BoxFileDao boxFileDao;
#Test
public void testUploadFile() {
boxFileDao.uploadFile();
verify(boxFileService).uploadFile(user, credential);
}
}
First you create your class under test BoxFileDao while injecting the mock for boxFileService into it. Afterwards you can create the spy on it.
For example:
BoxFileDao dao = new BoxFileDao();
dao.boxFileService = Mockito.mock(BoxFileService.class);
BoxFileDao spy = Mockito.spy(dao);
But the question would be why do you even want to do that? Is there a reason to spy on BoxFileDao, your class under test?
I want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest{
#Autowired
ComplicatedDependency complicatedDependency;
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class MockComplicatedDependency implements ComplicatedDepencency{
public MockComplicatedDependency(...){
// Inject other mocked objects into this mock
}
public String doSomthing(){
// This would be a mocked version of this function for testing
return "test";
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService(){
#InjectMock
private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl();
#Mock
ComplicatedDependency mockComplicatedDependency;
#BeforeClass
public static void init(){
mockComplicatedDependency = new MockComplicatedDependency(...);
}
#Test
public void testAttempt(){
serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example.
}
}
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl class for the ComplicatedDependency field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest {
#Autowired
ComplicatedDependency complicatedDependency;
public ServiceIWantToTestImpl() {
}
public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) {
this.complicatedDependency = complicatedDependency;
}
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class TestingTheService {
private static ServiceIWantToTestImpl serviceIWantToTest;
#BeforeClass
public static void init(){
serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency());
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
That is one way.
To make it work with Mockito, You could to use #Spy instead of #Mock like this:
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService {
#InjectMocks
private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl();
#Spy
private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency();
#BeforeClass
public static void init() {
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the #Spy annotation and make sure it's expected use is what you really need for your test.
I have written a testclass for a baseclass that uses a factory. I #Mocked the factory to return a Mock object.
It looks sort of like this.
class BaseClass{
SomeFactory factory;
public BaseClass(SomeFactory factory){
this.factory=factory;
}
public void parse(){
factory.createSomething();
}
}
Now my (working) testclass looks like this.
#RunWith(MockitoJUnitRunner.class)
public class BaseTest {
#Mock
SomeFactory factory;
#Mock
SomeCreation crateation;
BaseClass subject;
#Before
public void setUp(){
when(factory.createSomething()).thenReturn(someCreation);
subject = new BaseClass(factory);
}
#Test
testParse(){
subject.Parse();
verify(factory).createSomething();
}
}
This all works fine, but now i have extended BaseClass (lets call it SubClass) and added some functionality. My SubClass also uses an extended factory (SubFactory). So i also want to extend BaseTest and run the same tests, because it does the exact same thing and something extra.
so i overrode the setUp() like so:
class SubTest extends BaseTest{
#Mock
SubFactory subFactory;
#Mock
Something something;
#Override
public void setUp(){
when(subFactory.createSomething()).thenReturn(
factory = subFactory;
subject = new SubClass(subFactory);
}
}
This however doesn't work, because in the baseclass it throws an UnfinishedVerificationException saying:
Missing method call for verify(mock) here:
pointing to the verify in the BaseClass.
Any ideas on how to structure my test-cases that allows me to test the SubClass with the same tests as BaseClass?
Thank you,
Do not extend test cases! Even though there will be (lots of) duplicated code, it's easier to be read and followed.
So, the subclass test should not extend the BaseClass test, but rather re-use the tests on the functionality, which will not be overwritten in the subclass. Also, a getter for the factory would be needed to better customize the behavior on the mocked factory:
class SubClass extends BaseClass {
SubClass(SubFactory factory) {
super(factory);
}
SubFactory getFactory() { return factory; }
public void parse() {
getFactory().createSomething();
}
}
class SubTest {
#Mock
SubFactory subFactory;
#Mock
Something something;
#Mock
SubCreation someSubCreation;
SubClass subject = new SubClass(subFactory);
public void setUp() {
when(subFactory.createSomething()).thenReturn(someSubCreation);
}
}