I'm trying to write a unittest (test_myMethod) for one of my methods (myMethod) but I can't seem to get it to work. I get a NullPointer exception error with the code below. In my test it seems that the line myClass.otherMethod("hostName") in the unittest evaluates to Null so it can't do .getOSRevision(). Anyone know how I can get my unittest to pass?
MyClass.java
public class MyClass {
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
OtherMethod response = myClient.newMyMethodRevisionCall().call(
someObject.builder()
.withHostName(hostname)
.build()
);
return response;
}
}
MyClassTest.java
public class MyClassTest {
#Mock
private MyClient myClient;
#Mock
private MyMethodRevisionCall myMethodRevisionCall;
#Mock
private OtherMethod otherMethod;
private MyClass myClass;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
myClass = new MyClass(myClient);
}
// My failing unittest attempt
#Test
public void test_myMethod() {
when(myClass.otherMethod("hostName")
.getOSRevision()) //java.lang.NullPointerException happens on this line.
.thenReturn("TestString");
final String result = myClass.myMethod("TestString");
verify(myMethodRevisionCall, times(1)
}
}
You cannot use Mockito.when() on classes that are not mocked by Mockito. MyClass is not a mock. Instead you create an actual instance of it. Therefore, you need to actually run the code and not mock it. However, all dependencies of your class under test (MyClient in your case) you can mock.
This is a working example:
public class MyClass {
private MyClient myClient;
public MyClass(MyClient myClient) {
this.myClient = myClient;
}
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
return myClient.newMyMethodRevisionCall().call(new SomeObject(hostname));
}
}
class MyClassTest {
private MyClient myClient;
private MyClass myClass;
#BeforeEach
void setUp() {
myClient = mock(MyClient.class);
myClass = new MyClass(myClient);
}
#Test
public void test_myMethod() {
MyMethodRevisionCall myMethodRevisionCall = mock(MyMethodRevisionCall.class);
OtherMethod otherMethod = mock(OtherMethod.class);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
when(myMethodRevisionCall.call(any())).thenReturn(otherMethod);
when(otherMethod.getOSRevision()).thenReturn("revision");
final String result = myClass.myMethod("TestString");
assertEquals("revision", result);
verify(myMethodRevisionCall, times(1));
}
}
Related
I try write service test, for example, I have this ExamServiceImpl:
#Service
public class ExamServiceImpl implements ExamService {
#Autowired
private final SubjectService scoreService;
private final ScoreDAO scoreDAO;
#Autowired
public ExamServiceImpl(ScoreDAO scoreDAO) {
this.scoreDAO = scoreDAO;
}
#Override
public ResponseModel insertScore(RequestModel request) throws IOException {
SubjectModel subject = scoreService.getNameSubject(request);
ScoreModel score = new ScoreModel();
score.setStudentName(request.getStudentName);
score.setScore(request.getStudentScore);
score.setSubject(subject.getName);
int result = scoreDAO.insert(score);
return result;
}
}
Sample my test:
#SpringBootTest
public class ExamServiceImplTest {
#MockBean
private ScoreDAO scoreDAO;
#Autowired
private SubjectService subjectService;
#Autowired
private ExamService examService;
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
But output resultTest is 0. I try debugger, I found mock scoreDAO.insert() return 0 >> is not working.
And I try like this:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ExamServiceImplTest {
#Mock
private ScoreDAO scoreDAO;
#Mock
private SubjectService subjectService;
#InjectMocks
private ExamService examService = ExamServiceImpl(scoreDAO);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
It's not work too.
Please, could you help write me test methods? I covered with tests more simple other services.
Thank you!
It doesn't work because new ScoreModel() inside Mockito.when() and inside ExamServiceImpl are two different objects. If you want scoreDAO to return 1 for every ScoreModel passed to it you can use:
Mockito.when(scoreDAO.insert(Mockito.any(ScoreModel.class)).thenReturn(1);
I'm very new to writing unit tests for java. I want to write a test for method1:
public ClassA {
public String method1() {
ClassB classInst = ClassB.getInstance()
return classInst.doSomething()
}
}
Here, doSomething in classB connects to some databases and does an operation. This is my test class:
public TestClassA {
#Mock
private ClassB classBInst = mock(ClassB.class)
#InjectMocks
private ClassA classAInst = new ClassA()
#Before
public void setup() {
when(classInst.isClientEnabled()).thenReturn("ReturnStr");
}
#Test
public void testMethod1() {
String result = classAInst.method1();
assertEquals(result, "ReturnStr")
}
}
But the assert is failing because ClassB.doSomething() is not returning the mocked return value. Am I doing something wrong here? What is the correct way to mock classB here? I am using junit4 and mockito here
Hi. I have a service and a util classes as follows:
#Service
#RequiredArgsConstructor
public class DeviceService {
private final DeviceUtil deviceUtil;
public String getAllDevicesDeviceType(DeviceType deviceType){
final String appIdByDeviceType = deviceUtil.getAppIdByDeviceType(deviceType);
// ... actually I return smth different, but for simplicity just returning appIdByDeviceType
return appIdByDeviceType;
}
}
#Component
public class DeviceUtil {
private final String androidAppId;
public DeviceUtil(ApplicationProperties applicationProperties) {
ApplicationProperties.DeviceClient client = applicationProperties.getDeviceClient();
androidAppId = client.getAndroidAppId();
}
public String getAppIdByDeviceType(DeviceType deviceType) {
if (deviceType == DeviceType.ANDROID) return androidAppId;
throw InvalidInputException.of(ErrorCode.PARAMETER_INVALID, ErrorMessage.DEVICE_TYPE_INVALID);
}
}
In ApplicationProperties class I am getting static data from application.yml file. While running project, all are ok. But when I wrote a test for DeviceUtil class as follows:
#ExtendWith(MockitoExtension.class)
class DeviceUtilTest {
#Spy
private ApplicationProperties applicationProperties;
#InjectMocks
private DeviceUtil deviceUtil;
#Test
void getAppIdByDeviceType_Should_ReturnSuccess() {
String actualResult = deviceUtil.getAppIdByDeviceType(DeviceType.ANDROID);
assertNotNull(actualResult);
// assertThat(actualResult).isEqualTo(APP_ID);
}
}
Test failed with foloowing description:
expected: not null
org.opentest4j.AssertionFailedError: expected: not <null>
How can I solve the issue? Thanks in advance.
I have a class name ServiceLocator
public class ServiceLocator implements ApplicationContextAware {
private transient ApplicationContext _applicationContext;
private static ServiceLocator _instance = new ServiceLocator();
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_instance._applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return _instance._applicationContext;
}
public static Object findService(String serviceName) {
return _instance._applicationContext.getBean(serviceName);
}
}
I am trying to use that class to find Service into Approver class methods
public class ApproverService extends AbstractDataService implements IApproverService {
public void updateCompletedInboxStatus(String status) {
IInboxService inboxService = (IInboxService)ServiceLocator.findService("inboxService");
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
With that code i am trying to write Junit with PowerMockRunner
#RunWith(PowerMockRunner.class)
#PrepareForTest({ApproverService.class})
public class ApproverServiceTest {
#InjectMocks
ApproverService approverService;
#Mock
IInboxService inboxService;
#Mock
ServiceLocator serviceLocator;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
RequestAccessHeader reqHdr = new RequestAccessHeader();
reqHdr.setRequestStatus(AccessConstants.REQ_STATUS_HOLD_INT);
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(serviceLocator.findService("inboxService")).thenReturn(inboxService);
approverService.updateCompletedInboxStatus(status);
}
}
But I am getting null pointer
java.lang.NullPointerException
at com.alnt.fabric.common.ServiceLocator.findService(ServiceLocator.java:25)
at com.alnt.access.approver.service.ApproverServiceTest.updateCompletedInboxStatus(ApproverServiceTest.java:80)
Please help me to find the solution for that issue.
The static method is obviously not mocked.
The problem is most probably because you haven't add the to-be-mocked class in #PrepareForTest
Change it to #PrepareForTest({ApproverService.class, ServiceLocator.class})
Off-topics:
Although it compiles, calling static method by instance reference is not a good practice. Therefore the line should be when(ServiceLocator.findService(...)).thenReturn(inboxService).
Another problem is, you tried to use Singleton pattern but in wrong way. A singleton is suppose to return you an instance so the caller can call its instance method. Your findService is preferably an instance method and to be called as ServiceLocator.getInstance().findService(...). To further improve, unless you really need it to be a singleton, you should make it a normal object instance and inject to objects that need it (given you are already using Spring, I see no reason making a Singleton)
The setup for the static method is not mocked correctly
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServiceLocator.class}) //Prepare static class for mock
public class ApproverServiceTest {
#Mock
IInboxService inboxService;
#Mock
InboxItem item;
#InjectMocks
ApproverService approverService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(ServiceLocator.findService("inboxService")) //<-- NOTE static call
.thenReturn(inboxService);
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
Reference Mocking Static Method
The subject under test should actually be refactored to avoid the service locator anit-pattern / code smell and should follow explicit dependency principle via constructor injection.
public class ApproverService extends AbstractDataService implements IApproverService {
private IInboxService inboxService;
#Autowired
public ApproverService(IInboxService inboxService){
this.inboxService = inboxService;
}
public void updateCompletedInboxStatus(String status) {
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
That way the subject class is genuine about what it needs to perform its function correctly,
And the test can then be refactored accordingly
#RunWith(PowerMockRunner.class)
public class ApproverServiceTest {
#Mock
IInboxService inboxService;
#Mock
InboxItem item;
#InjectMocks
ApproverService approverService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
I m using mockito for junit. I have doubt while creating mock of object.
I have class called DBConnect. Where I need database properties like dbname, credentials etc.
This class is used by PatientDetails. Now when I am writing junit for PatientDetails. So I am using following code.
#RunWith(MockitoJUnitRunner.class)
public class PatientDetailsTest {
#Mock
DBConnect dbConnect
#Before
public void setUp()
{
PatientDetails testClass = new PatientDetails();
testClass.setDBConnect(dbConnect);
}
}
I can not get correct result with this.
You code seems fine to me. I've extended it slightly to include a test, so that it can be run. This works fine:
#RunWith(MockitoJUnitRunner.class)
public class PatientDetailsTest {
#Mock
DBConnect dbConnect;
#Before
public void setUp() {
when(dbConnect.sayHello()).thenReturn("works for me");
PatientDetails testClass = new PatientDetails();
testClass.setDBConnect(dbConnect);
}
#Test
public void testname() throws Exception {
System.out.println("foo");
}
private static interface DBConnect {
String sayHello();
}
private static class PatientDetails {
public void setDBConnect(DBConnect dbConnect) {
System.out.println(dbConnect.sayHello());
}
}
}
Output:
works for me
foo