AtUnit not able to create @Mock from concrete classes

25 views
Skip to first unread message

Doug Daniels

unread,
Apr 16, 2009, 4:13:11 PM4/16/09
to atunit
I'm trying to create an @Mock object from a concrete class with
EasyMock using the classextension.EasyMock, as described here:
http://jeantessier.com/SoftwareEngineering/Mocking.html#MockingClasses

But AtUnit doesn't seem to support that. Is there a way to configure
AtUnit to do that (or I could just extract the concrete class to an
interface).

Here's the error:
java.lang.IllegalArgumentException: com.webwars.addwars.ConcreteClass
is not an interface
at java.lang.reflect.Proxy.getProxyClass(Proxy.java:362)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
at org.easymock.internal.JavaProxyFactory.createProxy
(JavaProxyFactory.java:12)
at org.easymock.internal.MocksControl.createMock(MocksControl.java:
36)
at org.easymock.EasyMock.createStrictMock(EasyMock.java:28)
at atunit.easymock.EasyMockFramework.getValues(EasyMockFramework.java:
36)
at atunit.AtUnit.createTest(AtUnit.java:72)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod
(JUnit4ClassRunner.java:87)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods
(JUnit4ClassRunner.java:59)
at org.junit.internal.runners.JUnit4ClassRunner$1.run
(JUnit4ClassRunner.java:52)
at org.junit.internal.runners.ClassRoadie.runUnprotected
(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected
(ClassRoadie.java:44)
at org.junit.internal.runners.JUnit4ClassRunner.run
(JUnit4ClassRunner.java:50)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run
(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run
(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests
(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests
(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run
(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main
(RemoteTestRunner.java:196)



Here's an example:

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;

import atunit.AtUnit;
import atunit.Container;
import atunit.Mock;
import atunit.MockFramework;
import atunit.Unit;

import com.google.inject.Inject;
/**
* @author ddaniels
*
*/
@RunWith(AtUnit.class)
@MockFramework(MockFramework.Option.EASYMOCK) // tells AtUnit to use
EasyMock
@Container(Container.Option.GUICE)
public class ConcreteClassMockTest {

@Inject @Unit private TestClass testClass;

@Mock ConcreteClass concreteClass;

@Test
public void testClass() {
assertEquals(0, testClass.getConcreteClass().val);
}
}

class ConcreteClass {

public int val = 0;
}

class TestClass {

@Inject private ConcreteClass concreteClass;

public ConcreteClass getConcreteClass() {
return concreteClass;
}

public void setConcreteClass(ConcreteClass concreteClass) {
this.concreteClass = concreteClass;
}

}

Guðmundur Bjarni

unread,
Apr 17, 2009, 8:01:57 AM4/17/09
to atunit
I've just tried importing the classextensions.EasyMock and surely that
works as advertised. My only objection is that it requires that an
extra dependency is dragged in (easymock-classextension.jar) and that
is surely something that not everyone wants. The other option is to
provide an extra mock framework (@MockFramework
(MockFramework.Option.EASYMOCKCLASSEXTENSION)) which uses the
classextension.EasyMock.

I personally prefer the extra mock framework option, as it is then up
to the user which one they want. What do you think?

regards,
Guðmundur Bjarni

Logan Johnson

unread,
Apr 17, 2009, 8:13:17 AM4/17/09
to atu...@googlegroups.com
I've been resistant in the past to adding support for mocking concrete classes.   I use mocks partly because they help to point out design problems, and the need to mock a concrete class almost always indicates a missing interface.

That said, the objection isn't as strong if it's done as a separate mock framework from Option.EASYMOCK.

--Logan


2009/4/17 Guðmundur Bjarni <gudmundu...@gmail.com>

Guðmundur Bjarni

unread,
Apr 17, 2009, 8:26:31 AM4/17/09
to atunit
I agree with you about the "uglyness" of it. Also adding it as a
separate mock framework feels a bit polluting and nasty. :) As
EasyMock uses statics for creating mocks, there is really no "neat"
and easy way to do this cleanly. So I think I'm gonna stay away from
this one.


regards,
Guðmundur Bjarni


On Apr 17, 2:13 pm, Logan Johnson <logan.john...@gmail.com> wrote:
> I've been resistant in the past to adding support for mocking concrete
> classes.   I use mocks partly because they help to point out design
> problems, and the need to mock a concrete class almost always indicates a
> missing interface.
> That said, the objection isn't as strong if it's done as a separate mock
> framework from Option.EASYMOCK.
>
> --Logan
>
> 2009/4/17 Guðmundur Bjarni <gudmundur.bja...@gmail.com>

Doug Daniels

unread,
Apr 17, 2009, 11:08:01 AM4/17/09
to atu...@googlegroups.com
I'm on board with the ugliness and that mocking a concrete object points out a design problem, I've gone ahead and created an interface for my concrete dependency that I wanted to @Inject as a @Mock.

One place I did need to manually use a concrete class was in testing an HttpServlet and mocking out the ServletResponse.getWriter() (and maybe this is just my lack of understanding how to best use/test standard servlets)

If you want to test that your servlet handles an HttpRequest and sends back an expected HttpResponse how would you do this in the AtUnit or a Mock framework? I guess one answer is that you should have your business logic set everything up to write out to the Response PrintWriter or Outputstream and then validate that and assume the write() methods work fine.

    @Test
    public void testDoPostMessages() throws ServletException, IOException {
        List<Message> messages = new ArrayList<Message>();
        messages.add(mockMsg1);
        messages.add(mockMsg2);  
        servletManager.deliverMessage(mockMsg1, request, 3L);
        servletManager.deliverMessage(mockMsg2, request, 3L);
        //Stub out the response
        PrintWriter stubWriter = org.easymock.classextension.EasyMock.createNiceMock(PrintWriter.class);
        expect(response.getWriter()).andReturn(stubWriter);
       
        String jsonString = jsonConverter.toJSON(messages);       
        expect(request.getParameter(AJAXMessageServlet.JSONMSG)).andReturn(jsonString);
        expect(request.getParameter(AJAXMessageServlet.CONTEXT_ID)).andReturn("3");
       
        replay(request);
        replay(response);
        replay(servletManager);
       
        ajaxServlet.doGet(request, response);

        verify(request);
        verify(response);
        verify(servletManager);
    }

2009/4/17 Guðmundur Bjarni <gudmundu...@gmail.com>
Reply all
Reply to author
Forward
0 new messages