使用Mockito进行活动和场所的GWT MVP测试用例和GIN

时间:2012-09-06 05:19:00

标签: java gwt junit mvp mockito

我是带有GIN组合的活动和场所的GWT MVP模式的新手。我已经开始尝试使用Mockito为我的GWT项目编写一个JUnit测试用例。许多博客建议我不使用GWT测试用例因为它的性能所以我计划坚持使用Mockito。我正在为其中一位演示者写一个测试用例。由于我使用GIN为我的Presenter中的大部分内容创建实例,因此我必须模拟我的Gin Injector对象。我的Junit测试用例不允许我嘲笑Gin注入器。我在某地读到我们不能在Junit测试用例中使用Gin,而是我们必须使用Guice。我的问题是如何使用Mockito模拟我的Gin注射器?我找到了一些测试用例,它使用了与我的项目完全相同的模式,只是他们使用了Client Factory。在测试用例中,我无法用GIN替换客户端工厂。我在网上找到的代码如下,我必须在我的测试用例中用GIN注入器替换Client Factory。

@RunWith(MockitoJUnitRunner.class) 公共类ContactListActivityTest {

@Mock
private IClientFactory clientFactoryMock;

@Mock
private PlaceController placeControllerMock;

@Mock
private IContactListView contactListViewMock;

@Mock
private AcceptsOneWidget acceptsOneWidgetMock;

@Mock
private IContactServiceAsync contactServiceAsyncMock;

@Mock
private EventBus eventBusMock;

private List<Contact> contacts;
private Contact contact1;
private Contact contact2;

@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
    when(clientFactoryMock.getPlaceController()).thenReturn(placeControllerMock);
    when(clientFactoryMock.getContactListView()).thenReturn(contactListViewMock);
    when(clientFactoryMock.getContactService()).thenReturn(contactServiceAsyncMock);

    Answer<Void> answer = new Answer<Void>() {
        @Override
        public Void answer(InvocationOnMock invocation) {
            Object[] args = invocation.getArguments();
            AsyncCallback<List<Contact>> asyncCallback = (AsyncCallback<List<Contact>>) args[0];
            contact1 = new Contact();
            contact1.setFirstName("Kai");
            contact1.setLastName("Toedter");
            contact1.setEmail("kai@toedter.com");
            contact2 = new Contact();
            contact2.setFirstName("Kai2");
            contact2.setLastName("Toedter2");
            contact2.setEmail("kai2@toedter.com");
            final List<Contact> contacts2 = new ArrayList<Contact>();
            contacts2.add(contact1);
            contacts2.add(contact2);
            asyncCallback.onSuccess(contacts2);
            return null;
        }
    };

    doAnswer(answer).when(contactServiceAsyncMock).getAllContacts(any(AsyncCallback.class));

    // set the real contacts object, when clientFactory.setContacts is
    // called
    Answer<Void> setContactsAnswer = new Answer<Void>() {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            contacts = (List<Contact>) invocation.getArguments()[0];
            // System.out.println("answer() to setContacts(): " + contacts);
            return null;
        }
    };

    doAnswer(setContactsAnswer).when(clientFactoryMock).setContacts(any(List.class));

    // Return the real contacts object, when clientFactory.getContacts is
    // called
    Answer<List<Contact>> getContactsAnswer = new Answer<List<Contact>>() {
        @Override
        public List<Contact> answer(InvocationOnMock invocation) throws Throwable {
            return contacts;
        }
    };

    doAnswer(getContactsAnswer).when(clientFactoryMock).getContacts();
}

@Test
public void testGotoPlace() {
    ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(null), clientFactoryMock);

    ContactPlace contactPlace = new ContactPlace("kai@toedter.com");
    contactListActivity.goTo(contactPlace);

    verify(placeControllerMock).goTo(contactPlace);
}

@Test
public void testStartWithEmptyToken() {
    clientFactoryMock.setContacts(null); // force RCP
    ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(""), clientFactoryMock);
    contactListActivity.start(acceptsOneWidgetMock, eventBusMock);

    verify(contactListViewMock).setPresenter(contactListActivity);
    verify(contactListViewMock).initialize(contacts);
}

@Test
public void testStartWithToken() {
    String token = "kai@toedter.com";
    clientFactoryMock.setContacts(null); // force RCP

    ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(token), clientFactoryMock);
    contactListActivity.start(acceptsOneWidgetMock, eventBusMock);

    verify(contactListViewMock).setPresenter(contactListActivity);
    verify(contactListViewMock).initialize(contacts);
    verify(contactListViewMock).selectInitialContact(contact1);
    verify(eventBusMock).fireEvent(any(ContactViewEvent.class));
}

@Test
public void testMayStop() {
    ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(null), clientFactoryMock);
    contactListActivity.start(acceptsOneWidgetMock, eventBusMock);
    contactListActivity.mayStop();

    verify(contactListViewMock).setPresenter(null);
}

@Test
public void clientFactoryTest() {
    List<Contact> testList = new ArrayList<Contact>();
    clientFactoryMock.setContacts(testList);
    Assert.assertNotNull(clientFactoryMock.getContacts());
}

}

请帮助。

2 个答案:

答案 0 :(得分:1)

如果您的代码取决于Ginjector,那么您就遇到了问题:您没有注入direct dependencies。如果您需要一个对象工厂,请注入Provider

但在您的情况下,IClientFactory还可用作{em>共享状态,值持有者本地缓存 {1}};这意味着List<Contact>违反了single responsibility principle

因此,首先将本地缓存职责提取到自己的对象(例如IClientFactory对象或更通用的ContactListCache)中,然后注入该对象的实例。
当然,直接注入ValueHolder<List<Contact>>,视图和GWT-RPC服务。

但实际上,我会更进一步并重构代码以从缓存中提取检索或将服务器责任转移到其自己的PlaceController对象中(或者,当您使用时GWT-RPC,您可以将ContactListHolder接口实现为IContactServiceAsync生成的包装器,并添加缓存行为;请参阅http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html获取一些灵感。这会简化活动的代码。


作为旁注,此代码可能过多地使用了模拟:为什么不使用真实的GWT.create()(以及PlaceController方法spy()方法)和{{1} }或goTo(Place)

答案 1 :(得分:0)

我所做的是使用 GwtMockito ,这是Mockito的扩展。在我使用我的注射器的唯一一个类中,我的测试看起来像这样

@RunWith(GwtMockitoTestRunner.class)
public class AppControllerTest {

    AppController controller;

    @Mock
    EventBus eventBus;

    @Mock
    AppInjector injector;

    @Before
    public void setUp() throws Exception {
    }

    @Test
    public void shouldUseInjector() throws Exception {
        // Given
        controller = new AppController(eventBus, injector);

        // When
        controller.go();

        // Verify
        verify(injector).mainPresenter();
    }
}