mocking a recursive class - java

using Spring 2.0.3.RELEASE, JUnit Jupiter 5.7.0, Mockito 3.3.3
try to test method method01 of class Class01:
public class Class01 {
private RestConnector con;
public Class01(){
con = RestConnector.getInstance();
}
public Response method01(String x) {
Class01 example = new Class01();
String x = example.isAuthenticated();
// more stuff after this
}
public String isAuthenticated() throws IOException {
// I do stuff
return "a string";
}
}
In the test class have tried
public class Class01Test{
#Mock private Class01 class01Mock;
#Spy #InjectMocks private Class01 class01;
#Test
public void test() throws Throwable {
doReturn("I returned").when(class01). ??? stuck here .. always goes into the isAuthenticated method
Response result = class01.method01("a string");
}
}
Currently the test is always running the real method isAuthenticated.
How to setup a mock for the field example in method method01 so that the execute skips going into method isAuthenticated?

try to test method method01 of class Class01
Then you don't need mocks.
#Test
public void test() throws Throwable {
Class01 c = new Class01();
Response expected = ... ;
assertEquals(c.method01("input"), expected);
}
If you want to inject behaviour into example variable, you need to move it to a field
public class Class01 {
private RestConnector con;
private Class01 inner;
public Class01(){
con = RestConnector.getInstance();
}
Class01(Class01 c) {
this();
this.inner = c;
}
public Response method01(String x) {
String x = inner.isAuthenticated();
// more stuff after this
}
Along with a Mock
#RunWith(MockitoJunitRunner.class)
public class Class01Test{
#Mock Class01 class01Mock;
#Test
public void test() throws Throwable {
Response expected = ... ;
when(class01Mock.isAuthenticated()).thenReture(expected); ... // TODO: Setup
Class01 c = new Class01(class01Mock); // pass in the mock
assertEquals(c.method01("input"), expected);
}
However, unclear why you need a nested object of the same class when you appear to only need this.isAuthenticated()
Ideally, you'd also mock the RestConnector

Related

Mockito, MissingMethodInvocationException when run all tests in class

Here is my test class.
#ExtendWith(MockitoExtension.class)
class DishServiceTest {
static MockedStatic<DaoFactory> daoFactoryDummy;
static MockedStatic<FileUtil> fileUtilDummy;
#Mock
DaoFactory daoFactory;
#Mock
DishDao dishDao;
#Spy
DishService dishService;
#BeforeAll
static void setUp() {
fileUtilDummy = Mockito.mockStatic(FileUtil.class);
daoFactoryDummy = Mockito.mockStatic(DaoFactory.class);
}
#AfterAll
static void close() {
daoFactoryDummy.close();
fileUtilDummy.close();
}
#Test
void deleteWithImage_id0_success() {
daoFactoryDummy.when(ServiceManager::getInstance).thenReturn(daoFactory);
when(daoFactory.createDishDao()).thenReturn(dishDao);
long id = 2;
String deleteDir = "/dish-image/2";
dishService.deleteWithImage(id, deleteDir);
verify(dishDao, times(1)).delete(id);
fileUtilDummy.verify(() -> FileUtil.deleteDishFolder(deleteDir));
}
#Test
void update_idSet_success() {
daoFactoryDummy.when(ServiceManager::getInstance).thenReturn(daoFactory);
when(daoFactory.createDishDao()).thenReturn(dishDao);
Dish dish = new Dish(2, "testName",
"testDescription", Category.DRINKS, BigDecimal.TEN, "/image21");
dishService.saveOrUpdate(dish);
verify(dishDao, times(1)).update(dish);
verify(dishDao, times(1)).close();
}
}
I mock static methods like this because DishService class gets dao object from DaoFactory.
Here is an example of DishService method
public class DishService {
public void saveOrUpdate(Dish newDish) {
try (DishDao dishDao = DaoFactory.getInstance().createDishDao()) {
long newDishId = newDish.getId();
if (newDishId == 0) {
dishDao.save(newDish);
} else {
dishDao.update(newDish);
}
}
}
}
And of DaoFactory
public class JDBCDaoFactory extends DaoFactory {
DBManager dbManager = DBManager.getInstance();
UserDaoMapper userDaoMapper = new UserDaoMapper();
DishDaoMapper dishDaoMapper = new DishDaoMapper();
OrderDaoMapper orderDaoMapper = new OrderDaoMapper();
OrderItemDaoMapper orderItemDaoMapper = new OrderItemDaoMapper();
#Override
public UserDao createUserDao() {
return new JDBCUserDao(dbManager.getConnection(),
userDaoMapper);
}
#Override
public DishDao createDishDao() {
return new JDBCDishDao(dbManager.getConnection(), dishDaoMapper);
}
#Override
public OrderDao createOrderDao() {
return new JDBCOrderDao(dbManager.getConnection(), orderDaoMapper,
orderItemDaoMapper);
}
}
And here is the exception I have
org.mockito.exceptions.misusing.MissingMethodInvocationException:
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods
declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object. at
service.DishServiceTest.update_idSet_success(DishServiceTest.java:61)
Here is the line 61
The strangest thing here is that tests pass when I run them seperately, but if i press run all tests in class I get the exception above.

Mocking new object method call in Junit5

I have mocked another class method called Which is called at production like new B().somemethod (arg) has return type void and newD().anymenthod() it has return type inputstream
In the test method, I am doing mocking Like donothing().when(b). somemethod ();
And
When(d.anymehod()).thenreturn(inputstream);(here inputstrem i am providing)
Here I already did #Mock B b;
#Mock D d;
Here my test case run successfully but mocked method was also called at that time.
Here I didn't want to alter the production code only test cases implementation can be altered.
class TestSystem {
#InjectMock
System sys;
#Mock
B b;
#Mock
D d;
#BeforeEach
void setup() {
MockitoAnnotation.openMocks(this);
}
#Test
testModule() {
InputStrem input = null;
when(d.anymethod()).thenReturn(inputStrem);
doNothing().when(b).somemethod();
sys.module();
}
Class System{
public void module() {
//some code .....
new B().somemethod();
inputStrem = new D().anymethod(value);
}
Class B {
public void somemethod(){
//some code .....
}
}
Class D {
public InputStrem anymethod() {
//some code ......
}
}
Try to initialise Mock like this:
#InjectMocks
private System sys;
#Mock
B b;
#Mock
D d;
private AutoCloseable closeable;
#BeforeEach
void init() {
closeable = MockitoAnnotations.openMocks(this);
}
#AfterEach
void closeService() throws Exception {
closeable.close();
}
#Test
testModule(){...}

How to inject mocks into a class that has 1 constructor with parameters?

I have the following class (Condensed it to focus on issue instead of showing entire class):
#Component
public class ABCDEF {
private final Helper helper;
private final URI uri;
public ABCDEF(Helper helper, #Value("${endpoint.url}") URI uri) {
this.helper = helper;
this.uri = uri;
}
public void b(){
helper.toString();
}
}
For its test, I am looking to inject the mocks as follows but it is not working.
The helper comes up as null and I end up having to add a default constructor to be able to throw the URI exception.
Please advice a way around this to be able to properly inject the mocks. Thanks.
#RunWith(JUnitMockitoRunner.class)
public class ABCDEFTest {
#Mock
private Helper helper;
#InjectMocks
private ABCDEF abcdef = new ABCDEF(
helper,
new URI("test")
);
// adding just to be able to throw Exception
public ABCDEFTest() throws URISyntaxException {
}
#Test
public void b() {
abcdef.b();
}
}
Note: Using Mockito version 1.10.19. Will need to stick to this version.
This should work:
#RunWith(MockitoJUnitRunner.class)
public class ABCDEFTest {
#Mock
private Helper helper;
private ABCDEF abcdef;
#Before
public void setUp() throws URISyntaxException {
abcdef = new ABCDEF(
helper,
new URI("test")
);
}
#Test
public void b() {
abcdef.b();
}
}
Or, instead of using #RunWith, you can initialize mock inside setUp method:
public class ABCDEFTest {
private Helper helper;
private ABCDEF abcdef;
#Before
public void setUp() throws URISyntaxException {
helper = Mockito.mock(Helper.class);
abcdef = new ABCDEF(
helper,
new URI("test")
);
}
#Test
public void b() {
abcdef.b();
}
}

Mock object of super class in subclass using EasyMock

I have a class to be tested which is like this:
public class MainClass extends BaseClass {
public static int variableToBeAsserted= 0;
MainClass(ConfigClass config) {
super(config);
}
public void myMethod() {
List list = objectOfClass1inSuperClass.operation(objectOfClass2inSuperClass.method())
while(methodInSuperClass()) {
// doing operations with 'list'
variableToBeAsserted++;
}
}
// ..few other methods which I am not going to test.
}
I have suppressed the constructor of my BaseClass and my ConfigClass. Now my test class is like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestClass {
#Before
public void setUp(){
suppress(constructor(BaseClass.class))
suppress(constructor(ConfigClass.class))
}
#Test
public void testMyMethod(){
MainClass main = new MainClass(new ConfigClass(""));
List list1= new ArrayList();
test1.add("somevalues");
Class1inSuperClass ob1 = PowerMock.createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = PowerMock.createMock(Class2inSuperClass.class);
EasyMock.expect(ob2.method()).andReturn(getClass());
EasyMock.expect(ob1.operation(getClass())).andReturn(list1);
PowerMock.replayAll();
main.myMethod();
Assert.assertEquals(expectedValue, main.variableToBeAsserted);
}
}
Now I don't know why but my test case fails with a NullPointerException.
It tries to access objectofClass1inSuperClass and fails. I thought this will mock it. But it does not get mocked.
EDIT: I am writing only the test and I cannot change anything in BaseClass. However I have the option to modify the MainClass.
You have two ways to inject mock object to the object under the test.
Manually via WhiteBox
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class WhiteBoxApproachTestClass {
#Before
public void setUp() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
MainClass main = new MainClass(createMock(ConfigClass.class));
List<String> list1 = new ArrayList<>();
list1.add("somevalues");
Class1inSuperClass ob1 = createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = createMock(Class2inSuperClass.class);
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
Whitebox.setInternalState(main, "objectOfClass1inSuperClass", ob1);
Whitebox.setInternalState(main, "objectOfClass2inSuperClass", ob2);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
And via #TestSubject (http://easymock.org/user-guide.html#mocking-annotations)
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestSubjectApproachTestClass {
#Mock(fieldName = "objectOfClass1inSuperClass")
private Class1inSuperClass ob1;
#Mock(fieldName = "objectOfClass2inSuperClass")
private Class2inSuperClass ob2;
#TestSubject
private final MainClass main = new MainClass(createMock(ConfigClass.class));
#BeforeClass
public static void before() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
List<String> list1= new ArrayList<>();
list1.add("somevalues");
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
EasyMockSupport.injectMocks(main);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
Full code you may find here.

How to initialize mocked object?

Lets say I have the following code:
Mocked object class
public class SomeClass {
private Foo someField;
public SomeClass {
someField = new Foo();
}
public Foo getSomeField { return someField; }
public void getSomething() {}
public boolean doSomething(Object object) {}
}
Next I have test suite
public class TestSuite {
private ClassToTest classToTest;
private SomeClass mock;
#Before
public void setUp() {
classToTest = new ClassToTest();
mock = EasyMock.createMock(SomeClass.class);
}
#Test
public void testMethod() throws Exception {
mock.getSomething();
EasyMock.replay(mock);
classToTest.methodToTest(mock); //Where methodToTest accepts SomeClass and int
EasyMock.verify(mock);
}
}
And method which is being tested
public void methodToTest(SomeClass a) {
//Logic here
Foo b = a.getSomeField();
b.do(); // <--- null pointer exception here because someField isn't initialized
a.getSomething(); // <--- thing I want to test if it is being called, but can't due to exception prior to this line
//Logic after
}
I am stuck.. So yea basically SomeClass isn't initialized like I wanted to. Is there any workaround? Or maybe any other frameworks which can do something like that?
Your methodToTest calls a.getSomeField(), but the setup part of your test doesn't expect that call. You want something like:
Foo foo = new Foo();
EasyMock.expect(mock.getSomeField()).andReturn(foo);
Or to stub the call:
Foo foo = new Foo();
EasyMock.expect(mock.getSomeField()).andStubReturn(foo);
(before your call to mock.getSomething()).
See this question for the differences between andReturn and andStubReturn.

Categories

Resources