How to mock a private dao variable?

你。 提交于 2020-01-02 01:43:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!