Do not #Mock me #Java #Junit #Automation

We all use jUnit, and I see many times developers say for to achieve proper testing for their code mocking is required as many components of their products dependent on specific environment which they can’t achieve in the environment they are testing. I beg to differ.

First thing first, we are testing our product component, and if we mock specific/many sets of components how could we assure our test result is 100% correct and the code doesn’t have any bug? Got this example from internet, they are mocking a Book object like below,

@BeforeClass

public static void setUp(){
//Create mock object of BookDAL
mockedBookDAL = mock(BookDAL.class);

//Create few instances of Book class.
book1 = new Book("8131721019","Compilers Principles",
Arrays.asList("D. Jeffrey Ulman","Ravi Sethi", "Alfred V. Aho", "Monica S. Lam"),
"Pearson Education Singapore Pte Ltd", 2008,1009,"BOOK_IMAGE");

book2 = new Book("9788183331630","Let Us C 13th Edition",
Arrays.asList("Yashavant Kanetkar"),"BPB PUBLICATIONS", 2012,675,"BOOK_IMAGE");

//Stubbing the methods of mocked BookDAL with mocked data.
when(mockedBookDAL.getAllBooks()).thenReturn(Arrays.asList(book1, book2));
when(mockedBookDAL.getBook("8131721019")).thenReturn(book1);
when(mockedBookDAL.addBook(book1)).thenReturn(book1.getIsbn());
when(mockedBookDAL.updateBook(book1)).thenReturn(book1.getIsbn());
}

Come on, if you are deciding statically what you are expecting in case of specific method call how is it going to give you production level confidence?

Mock it like you didn’t

I faced same issues in my code also. Now we have to understand your requirement and specification first. Are you following TDD? Are you designing your framework from scratch or is it already designed? Are you testing a third party application?

In my case I was the sole developer for my framework, (yes once published, others are bound to use it 🙂 ). I designed my framework in below way,

server_Test

Below is the code snippet what server class does,


    public void createSomething(SomeObject someObject) {
        //Some Code here and there
        session = getHttpSession();
	//some more codes here and there
    }

So here is one of mu multiple issues, I don’t have an httpSession object in my test environment. But I have designed the class such a way that I can actually extends this class and override getHttpSession() method. I do not need to override or mock the createSomething method. Below is a bad example of same class where, it is quite impossible to use my solution.

private something;
    public void createSomething(SomeObject someObject) {
        //Some Code here and there
        session = something.session;
	//some more codes here and there
    }

Don’t think we can’t do 🙂 . But first thing first, design your classes such a way that minimal overriding works, and you need to override only data field/ pojos but not operations.

Now in above class I will see first in httpSession object what all fields we are using and then we will create our own httpSession. I see we are updating session attributes, for the operation to show some status in UI. So below is my httpSession,


/**
 * @author Abhinaba Basu
 * a mock class that represents httpsession
 */
public class FakeHttpSession implements javax.servlet.http.HttpSession {

    private Map<String, Object> attributes = new HashMap<String, Object>();

    public FakeHttpSession() {

    }

    @Override
    public long getCreationTime() {
        // TODO Implement this method
        return 0L;
    }

    @Override
    public String getId() {
        // TODO Implement this method
        return null;
    }

    @Override
    public long getLastAccessedTime() {
        // TODO Implement this method
        return 0L;
    }

    @Override
    public ServletContext getServletContext() {
        // TODO Implement this method
        return null;
    }

    @Override
    public void setMaxInactiveInterval(int i) {
        // TODO Implement this method
    }

    @Override
    public int getMaxInactiveInterval() {
        // TODO Implement this method
        return 0;
    }

    @Override
    public HttpSessionContext getSessionContext() {
        // TODO Implement this method
        return null;
    }

    @Override
    public Object getAttribute(String string) {
        // TODO Implement this method
        return attributes.get(string);
    }

    @Override
    public Object getValue(String string) {
        // TODO Implement this method
        return null;
    }

    @Override
    public Enumeration getAttributeNames() {
        // TODO Implement this method
        return null;
    }

    @Override
    public String[] getValueNames() {
        // TODO Implement this method
        return new String[0];
    }

    @Override
    public void setAttribute(String string, Object object) {
        attributes.put(string, object);

    }

    @Override
    public void putValue(String string, Object object) {
        // TODO Implement this method

    }

    @Override
    public void removeAttribute(String string) {
        attributes.remove(string);
    }

    @Override
    public void removeValue(String string) {
        // TODO Implement this method
    }

    @Override
    public void invalidate() {
        // TODO Implement this method
    }

    @Override
    public boolean isNew() {
        // TODO Implement this method
        return false;
    }
}

And now I need to override the server class to use my httpSession,


public class TestClass extends ServerClass {

    private HttpSession session = null;

public TestClass(){
    session = FakeHttpSession();

}

    /**
     * Create and return a mock http session as we are not in server side
     * @return
     */
    protected HttpSession getHttpSession(){
        return session;
    }

}

So with this, we are mocking only httpSession, we are not dependent on any thirdparty jars, we are not writing multiple lines of codes to test, once written, we can use the above classes multiple times.

Private Field/methods? Use reflection

Another problem people face while testing the codes, that are badly written/legacy or if you are a tester and testing some third party code, i.e. your class is final, which is having some private methods/fields you need to call/update to make sure your test cases go fine. Simple solution use reflection (but carefully).

In below example I need to update something, which can only be updated after a web service call, again remember I am in my test environment.


Field privateStringField;
                try {
                    privateStringField = Subject.class
                            .getDeclaredField("something");
                    privateStringField.setAccessible(true);
                    privateStringField.set(authenticatedSubject, somevalue);
                } catch (SecurityException e) {
                    //log
                } catch (NoSuchFieldException e) {
                    //log
                } catch (IllegalArgumentException e) {
                    //log
                } catch (IllegalAccessException e) {
                    //log
                }

Isn’t it quite simple? Feel like Supreman when you have all the controls and powers, don’t care if some open source guy suddenly changes their api. 😛

Still can’t manege

– I understand everything, but I still can’t manage, It is a third party product, I don’t have any access and I am not sure about the reflection also, even if I know, it won’t help, I don’t have that much time to write a framework.

– Server side?

– Yes, what to do now other than mocking?

– Go to stackoverflow, read the answers in that page. See what I was saying, Cactus is good but outdated (as they told), but it is not outdated. They are not upgrading framework due to less community members. You can still use cactus from here.

– Also read this article for better technical gain and chose what you want, but don’t please don’t mock.

 

 

You can follow me on Twitter, add me to your circle on Google+ or like our Facebook page to keep yourself updated on all the latest from Photography, Technology, Microsoft, Google, Apple and the web.

Leave a comment