问题
I have a dao.create()
call that I want to mock when testing a method.
But I am missing something as I'm still getting NPE. What is wrong here?
class MyService {
@Inject
private Dao dao;
public void myMethod() {
//..
dao.create(object);
//
}
}
How can I mock out the dao.create() call?
@RunWith(PowerMockRunner.class)
@PrepareForTest(DAO.class)
public void MyServiceTest {
@Test
public void testMyMethod() {
PowerMockito.mock(DAO.class);
MyService service = new MyService();
service.myMethod(); //NPE for dao.create()
}
}
回答1:
You are not injecting the DAO. With mockito you can change your test class to use @InjectMocks and use mockito runner.
@RunWith(MockitoJUnitRunner.class)
public void MyServiceTest {
@Mock
private Dao dao;
@InjectMocks
private MyService myService;
...
}
You can read more about InjectMocks at Inject Mocks API
Simpler way is changing your injection to injection by constructor. For example, you would change MyService to
class MyService {
...
private final Dao dao;
@Inject
public MyService(Dao dao) {
this.dao = dao;
}
...
}
then your test you could simple pass the mocked DAO in setup.
...
@Mock
private Dao dao;
@Before
public void setUp() {
this.dao = mock(Dao.class);
this.service = new MyService(dao);
}
...
now you can use verify
to check if create
was called, like:
...
verify(dao).create(argThat(isExpectedObjectBeingCreated(object)));
}
private Matcher<?> isExpectedObjectBeingCreated(Object object) { ... }
Using injection by constructor will let your dependencies clearer to other developers and it will help when creating tests :)
回答2:
You still need to set the dao field with your mock. You can use reflection to this.
回答3:
You need to inject/set the mocked object DAO in your service class.
If it is a spring based project, you may have a look @ Spring Junit Testrunner
回答4:
If you use new MyService()
the Dao is never injected. For the Dao to be injected you need to load the MyService via an ApplicationContext
(Spring) or an Injector
(Guice). Like you would in your normal application.
回答5:
As others have already said, you need to set the dao
field in your MyService
class in some fashion. I'm unsure the mechanism to allow for a compound runner on your test to use both Powermock and a DI framework runner (assuming Powermock is required), but as long as you're already using PowerMock (for reasons unclear in the given example), you could avail yourself of the Whitebox class to set the dao more manually.
public void testMyMethod() {
Dao dao = mock(Dao.class)
doNothing().when(dao).create(anyObject())); //assuming no return val for dao.create()
MyService service = new MyService();
Whitebox.setInternalState(service, "dao", dao);
service.myMethod();
}
来源:https://stackoverflow.com/questions/13645571/how-to-mock-a-private-dao-variable