I'm trying to understand JMockit but still I'm running into walls.
This is a class I want to test:
#Stateless
public class VerfahrensArchivService {
#PersistenceContext
private EntityManager em;
public void storeAndUpdateVerfahren(List<Verfahren> pVerfahrenToStore) {
if (pVerfahrenToStore == null){
throw new IllegalArgumentException("pVerfahrenToStore darf nicht null sein!");
}
for (Verfahren verfahren : pVerfahrenToStore) {
Verfahren storedCopy = getVerfahrenByExterneID(verfahren.getFremdsystem(), verfahren.getExterneId());
if (storedCopy == null){
//Ein neues Verfahren wurde gefunden!
em.persist(verfahren);
}else{
}
}
}
}
This is how my test looks like:
public class VerfahrensArchivServiceTest {
#Tested
private VerfahrensArchivService archiveService;
#NonStrict //Also tried simple #Mocked
private EntityManager em;
#Test
public void should_store_new_verfahren_to_persistence_layer(){
List<Verfahren> listeMitEinemNeuenVerfahren = new ArrayList<Verfahren>();
Verfahren v = new Verfahren();
v.setId(0);
v.setExterneId("Neu");
v.setFremdsystem(Verfahren.FREMDSYSTEM_P);
listeMitEinemNeuenVerfahren.add(v);
new NonStrictExpectations(archiveService) {
{
//simulate that nothing was found in the db
archiveService.getVerfahrenByExterneID(anyString, anyString);result = null;
}
};
new Expectations() {
{
em.persist(any);
}
};
archiveService.storeAndUpdateVerfahren(listeMitEinemNeuenVerfahren);
}
}
The test fails because EntityManager is null in the moment of calling em.persist().
Why?
Is the test structured the right way? If not, could you show me how I do better?
I really believe that JMockit will help me be more productive in a TDD way. But I need to understand how to use it correctly.
I read the #Tested Javadoc little bit more carefully. There it states, that you could use test method parameters to setup the #Tested/class under test. Just declare a #Incectable parameter of the type you need. Read the #Tested javadoc to find out how the params are matched to the uninitialized fields.
so, my test works with this:
#Test
public void should_store_new_verfahren_to_persistence_layer(#Injectable final EntityManager em){
List<Verfahren> listeMitEinemNeuenVerfahren = new ArrayList<Verfahren>();
Verfahren v = new Verfahren();
v.setId(0);
v.setExterneId("Neu");
v.setFremdsystem(Verfahren.FREMDSYSTEM_P);
listeMitEinemNeuenVerfahren.add(v);
new NonStrictExpectations(archiveService) {
{
archiveService.getVerfahrenByExterneID(anyString, anyString);result = null;
}
};
new Expectations() {
{
em.persist(any);
}
};
archiveService.storeAndUpdateVerfahren(listeMitEinemNeuenVerfahren);
}
Related
I have a tricky situation. I am using MVP architecture for android but thats not important. I have a class called DoStandardLoginUsecase that basically just connects to a server with login info and gets a access token. i am trying to test it. But the problem is the context that i am passing in to it so i can initialize dagger.
public class DoStandardLoginUsecase extends BaseUseCase {
#Inject
UserDataRepository mUserDataRepo;
private StandardLoginInfo loginInfo;
public DoStandardLoginUsecase(Context context) {
/* SEE HERE I AM USING A APPLICATION CONTEXT THAT I PASS TO DAGGER
*/
((MyApplication)context).getPresenterComponent().inject(this);
}
#Override
public Observable<Login> buildUseCaseObservable() {
return mUserDataRepo.doStandardLogin(loginInfo);
}
public void setLoginInfo(StandardLoginInfo loginInfo) {
this.loginInfo = loginInfo;
}
}
and here is the test i have so far:
public class DoStandardLoginUsecaseTest {
DoStandardLoginUsecase standardLoginUsecase;
StandardLoginInfo fakeLoginInfo;
TestObserver<Login> subscriber;
MockContext context;
#Before
public void setUp() throws Exception {
//now when i create the object since its a mock context it will fail when it tries to call real things as these are stubs. So how do i test this object. how do i create an instance of this object ? I am willing to use [daggerMock][1] if that helps also.
standardLoginUsecase = New DoStandardLoginUsecase(context);
fakeLoginInfo = new StandardLoginInfo("fred#hotmail.com","Asdfgh4534");
subscriber = TestObserver.create();
}
#Test
public void buildUseCaseObservable(){
standardLoginUsecase.seLoginInfo(fakeLoginInfo);
standardLoginUsecase.buildUseCaseObservable().subscribe(subscriber);
subscriber.assertNoErrors();
subscriber.assertSubscribed();
subscriber.assertComplete();
}
}
I would do the test like this:
public class DoStandardLoginUsecaseTest {
private DoStandardLoginUsecase target;
private MyApplication contextMock;
#Before
public void beforeEach() {
contextMock = Mockito.mock(MyApplication.class);
// Note that you need to mock the getPresenterComponent
// but I don't know what it returns.
target = new DoStandardLoginUsecase(contextMock);
}
#Test
public void buildUseCaseObservable() {
UserDataRepository userDataMock = Mockito.mock(UserDataRepository.class);
StandardLoginInfo loginInfoMock = Mockito.mock(StandardLoginInfo.class);
target.mUserDataRepo = userDataMock;
target.setLoginInfo(loginInfoMock);
Observable<Login> expected = // create your expected test data however you like...
Mockito.when(userDataMock.doStandardLogin(loginInfoMock)).thenReturn(expected);
Observable<Login> actual = target.buildUseCaseObservable();
Assert.areSame(actual, expected);
}
}
I am writing unit tests for my project, but facing some difficulties when calling methods, which work with database. Currently I want to check a method that gets the list of publications that are of users interest, but I am getting NullPointerException:
public class TestPubManager {
private PubManager pFunc;
#Before
public void initialize() {
EntityManager manager = PersistenceManager.INSTANCE.getEntityManager();
em.getTransaction().begin();
PubManager pManager = new PubManager(manager);
}
#Test
public void testGetInterestPubs() {
int res = pManager.getInterestPubs(2).size();
assertEquals(20, res);
}
}
NullPointerException is on the line with int res = pManager.getInterestPubs(2).size();. What am I doing wrong way?
I have found a solution. So the issue was in the constructor - it was not initializing in #Before annotation, but when I put it inside the test, everything worked out fine.
public class TestPubManager {
private PubManager pFunc;
EntityManager manager = PersistenceManager.INSTANCE.getEntityManager();
#Before
public void initialize() {
em.getTransaction().begin();
}
#Test
public void testGetInterestPubs() {
PubManager pManager = new PubManager(manager);
int res = pManager.getInterestPubs(2).size();
assertEquals(20, res);
}
}
I am trying to mock a method of a private field that has a return type of void. In my test, I am trying to mock aClass.doSomething() to throw an IllegalStateException and I need to verify that recover() is called. Here is an example:
public class ClassToTest implements Runnable {
private ClassToMock aClass;
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover(){
logger.info("I am recovering");
}
}
I have done each piece separately:
Mock a method call of a private field
Mock a method that has void return type
Throw exception
Verify a private method call
but I wasn't able to put all together. Any help is appreciated
I thought I'd elaborate GhostCat's comments:
Stay with Mockito
Mockito is more than a mocking framework - it's a discipline. If you read carefully the documentation for Mockito and restrain yourself from resorting to PowerMock et al you will learn good OOP practice.
Read how to do dependency injection with constructors
Primum non nocere - first refactor your code like this:
public class ClassToTest implements Runnable {
private final ClassToMock aClass;
private final Logger logger;
//injection of collaborators through the constructor
public ClassToTest(ClassToMock aClass, Logger logger) {
this.aClass = aClass;
this.logger = logger;
}
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover() { //there is no need for this method to be public - see Effective Java item 13
logger.info("I am recovering");
}
}
Now your code is testable using Mockito without resorting to more complex mocking frameworks:
//mocks
#Mock ClassToMock classToMock;
#Mock Logger mockLogger;
//system under test
ClassToTest classToTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks();
classToTest = new ClassToTest(classToMock, mockLogger);
}
#Test
public void whenRun_thenDoesSomethingWithSomeParameter() {
//act
classToTest.run();
//assert
verify(classToMock).doSomething(eq("some parameter"));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsError() {
//arrange
IllegalStateException e = new IllegalStateException();
when(classToMock.doSomething(anyString()).thenThrow(e);
//act
classToTest.run();
//assert
verify(mockLogger).error(eq("Something bad happened"), same(e));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsRecovery() {
//arrange
when(classToMock.doSomething(anyString()).thenThrow(new IllegalStateException());
//act
classToTest.run();
//assert
verify(mockLogger).info(eq("I am recovering"));
}
i wanted to write some tests for the method shown in the code below. I'm mocking dependencies with JMockit. For whatever reason i am getting a NullPointerException all the time and i really don't understand why that happens. I'm new to JMockit and in mocking dependencies in general. Stack Trace just shows NullPointerException thrown at line new NonStrictExpectations()
.
Method to test:
#Override
public boolean addSubject(User user, Schedule schedule, SchoolSubject subject) {
final boolean result = schedule.addSubject(subject.getHourTime(), subject);
scheduleDAO.update(schedule);
if (subject.getTeacher() != null && !subject.getTeacher().trim().isEmpty()) {
for (final TeacherEntry teacher : user.getTeachers()) {
if (subject.getTeacher().equals(teacher.getName())) {
teacher.getSubjects().add(subject.getName());
teacherDAO.update(teacher);
}
}
}
try {
userDAO.update(user);
} catch (final DuplicateUniqueFieldException e) {
throw new UnexpectedUniqueViolationException(e);
}
}
Test method:
//imports not copied
public class ScheduleManagerTest {
#Tested
ScheduleManager manager;
#Injectable
UserDAO userDAO;
#Injectable
ScheduleDAO scheduleDAO;
#Injectable
TeacherEntryDAO teacherDAO;
#Injectable
SchoolSubjectDAO schoolSubjectDAO;
#Mocked
Schedule schedule;
#Mocked
SchoolSubject subject;
#Mocked
User user;
#Test
public void testAddSubject() throws DuplicateUsernameException, DuplicateEmailException {
new NonStrictExpectations() {
{
schedule.addSubject(anyInt, (SchoolSubject) any);
result = true;
scheduleDAO.update((Schedule) any);
subject.getTeacher();
result = anyString;
subject.getTeacher().trim().isEmpty();
result = false;
user.getTeachers();
result = (ArrayList<TeacherEntry>) any;
teacherDAO.update(((TeacherEntry) any));
userDAO.update((User) any);
};
};
assertTrue(manager.addSubject(user, schedule, subject));
}
}
I think i'm doing something pretty wrong :(
It's hard to know what is going wrong based on the description, but here's a guess:
Mocked objects will return null in their methods by default. You'll get a null pointer here:
subject.getTeacher().trim()
because getTeacher() will return null. To return a teacher, you'll have to either use a real subject or do further mocking with
Mockito.when(subject.getTeacher()).thenReturn(new Teacher());
You need to add #RunWith(JMockit.class) to your class
#RunWith(JMockit.class)
public class ScheduleManagerTest {
...
I have been trying to run the following test using mockito and junit and I keep on getting "java.lang.NullPointerException: name must not be null"
Can anyone tell me why this is happening?
On debugging, I found out that this exception is thrown when the test executes the following statement in isStopValid(String) method:
FacilityValidationUtil facUtil = new FacilityValidationUtil();
#RunWith(MockitoJUnitRunner.class)
public class MyFormTest{
#InjectMocks MyForm form = new MyForm();
#Mock FacilityValidationUtil facUtil;
#Test
public void testIsStopValid() throws FinderException{
when(facUtil.isFacilityValid("")).thenReturn(false);
form.setOrigin("");
assertEquals(false, form.isStopValid(form.getOrigin()));
}
}
Class with method to be tested:
public class MyForm{
FacilityValidationUtil facUtil = new FacilityValidationUtil();
public boolean isStopValid(String stop){
try {
return facUtil.isFacilityValid(stop);
} catch (FinderException e) {
log.error("Error finding the stop. "+e.getCause());
return false;
}
}
}
public class FacilityValidationUtil{
private FacilityDAO facilityDao = new HibernateFacilityDAO();
public boolean isFacilityValid(String facility) throws FinderException{
boolean test;
FacilityImpl facilityImpl = facilityDao.findFacilityByNassCode(facility);
test = (facilityImpl==null)?false : true;
return test;
}
}
public class HibernateFacilityDAO extends HibernateAbstractDeltaDAO implements FacilityDAO {
public HibernateFacilityDAO() {
super(false);
}
}
Short Answer: You are trying to mock a variable (facUtil) that is local to your isStopValid method, so the mock version of this object in your test is never going to be called because you are 'newing it up" each time.
Long Answer: It looks like you are trying to mock the call to your FacilityValidationUtil class, and if this is the case, then you need to either make the class a field so that Mockito can inject the object by reflection (if this object is thread safe, which it looks like it is) or explore a mocking framework like PowerMockito that will allow you to mock a constructor (google for PowerMockito when new).
PowerMockito.whenNew(FacilityValidationUtil.class).withNoArguments().thenReturn(facUtil);
Mockito doesn't support any mocking of constructor args by default.
EDIT
If you are still having trouble, then I would suggest starting with a smaller example. I've put together one for you that works and uses the code you are trying to test (It's using inner classes though, which Mockito has some quirky rules about, but I'm just doing it to compress the example).
#RunWith(MockitoJUnitRunner.class)
public class MyFormTest {
#InjectMocks
private MyForm form = new MyForm();
#Mock
private FacilityValidationUtil facUtil;
#Test
public void testIsStopValid_false() {
when(facUtil.isFacilityValid("")).thenReturn(false);
assertEquals(false, form.isStopValid(""));
}
#Test
public void testIsStopValid_true() {
when(facUtil.isFacilityValid("")).thenReturn(true);
assertEquals(true, form.isStopValid(""));
}
public class MyForm {
private FacilityValidationUtil facUtil = new FacilityValidationUtil();
public boolean isStopValid(String stop) {
try {
return facUtil.isFacilityValid(stop);
} catch (FinderException e) {
return false;
}
}
}
public class FacilityValidationUtil {
public boolean isFacilityValid(String facility) throws FinderException {
throw new RuntimeException(facility);
}
}
public class FinderException extends RuntimeException {
public FinderException(String message) {
super(message);
}
}
}
What's really important is that your mock is not getting injected correctly. Until you get that resolved, you are going to keep getting the same error. Set a break point in your MyForm at the point you call facUtil.isFaciltyValid and look at the object. It should be a mockito object, not your class.
Good luck.