Showing posts with label JUnit. Show all posts
Showing posts with label JUnit. Show all posts

Tuesday, April 26, 2011

Testing Struts 2 Actions with JUnit

I've been trying my best to stick closely to the Test-Driven Development process with my current project.  A couple of my previous blog posts detail my experiences setting up JUnit and later testing Hibernate code with JUnit.

I'm currently working with Struts 2 and I have been researching methods for testing my Actions.  The struts.apache.org website has a nice little tutorial detailing the StrutsTestCase and the Struts 2 JUnit plugin.  I searched for more online resources on this topic but it became quickly apparent that most examples include Stuts 2, JUnit and Spring.  I'm not using Spring in this project and I haven't had the opportunity to get up to speed on the Spring framework yet.  Therefore, a lot of the examples I found were not helpful for me right now.

One concern I had about using the StrutsTestCase is that its Sourceforge project page hasn't been updated in years.  It still proudly displays "Now supporting Struts 1.2 and 1.3!"  However, I decided to give it a try since the Struts 2 documentation offers a tutorial and the struts2-junit-plugin-2.2.1.1.jar is included in the current Struts 2 distribution.

I modified the sample code from the Struts 2 tutorial to suit my needs.

public void testCreateTagFail() throws Exception {
    request.setParameter("name", "");
    ActionProxy proxy = getActionProxy("/createtag.action");
    TagAction tagAction = (TagAction) proxy.getAction();
    proxy.execute();

    assertTrue("Problem There were no errors present in fieldErrors but there should have been one error present", tagAction.getFieldErrors().size() == 1);
    assertTrue("Problem field 'name' not present in fieldErrors but it should have been",
            tagAction.getFieldErrors().containsKey("name") );

}

I had some compile errors and needed to add spring-test-2.5.6.jar and spring-core-2.5.6.jar to my build path.  Both of these jars are included in the Struts 2.2.1.1 distribution.

The method above is quite simple and just tests the Action's validation() method to confirm it returns a FieldError when a value for the Tag Name is missing.

Below is a method that gave me a lot of trouble:
    public void testCreateTag() throws Exception {

        request.setParameter("name", "my tag name");
        ActionProxy proxy = getActionProxy("/createtag.action");
        TagAction tagAction = (TagAction) proxy.getAction();
        String result = proxy.execute();

        assertTrue("Problem There were errors present in fieldErrors but there should not have been any errors present", tagAction.getFieldErrors().size() == 0);
        assertEquals("Result returned form executing the action was not success but it should have been.", "success", result);
    }

This JUnit test caused the Action to throw a Null Pointer exception when I tried to run it.  The problem is the Action expects to find a Hibernate SessionFactory object in the ServletContext.  (This earlier blog post explains my methodology for adding the Hibernate SessionFactory to the ServletContext.)  Since the StrutsTestCase is running outside a real container, using a mock container, the Action is not finding the SessionFactory and returning Null instead.

I did some research and determined I had a few options to resolve this problem.  First, as I mentioned in a previous blog post, I would be better off using mock database objects or DBUnit rather than testing against Hibernate and my actual relational database.  I may do that in the future, but it's not going to happen now.  :)

Another option would be to add the SessionFactory to the mock ServletContext and pass that to the Action through the StrutsTestCase.  This is an option I probably should have pursued and I would love to see some example code for this.

Of course, I went with the third and probably least elegant option.  I created a base class that extends ActionSupport and added a method getSession() which tries to retrieve the the Hibernate SessionFactory from the ServletContext and creates a new one if it fails.
public class FlashCardsAppBaseAction extends ActionSupport{

    protected Session getSession() {

        //try to get hibernate session from the servlet context
        SessionFactory sessionFactory =

        (SessionFactory) ServletActionContext.getServletContext()
            .getAttribute(FlashCardAppConstants.HibernateSessionFactoryName);

        // if the sessionFactory is null then create a new one
        if (sessionFactory == null) {
            sessionFactory = HibernateUtil.createSessionFactory();

            // add the Hibernate SessionFactory to the ServletContext
            ServletActionContext.getServletContext().setAttribute(FlashCardAppConstants.HibernateSessionFactoryName, sessionFactory);
                }

        // get a session from the session factory
        return sessionFactory.openSession();
        }
}

I refactored my Actions to extend the new FlashCardsAppBaseAction and they get a handle to the SessionFactory using the super.getSession() method as seen below.

@SkipValidation
public String listTags() {

    try {

        // get a handle to a Hibernate session
        Session session = getSession();

        // get a list of Tags from the data tier
        TagPersister tagPersister = new TagPersister();

        tagList = tagPersister.getTags(session);

        return "success";

    } catch (HibernateException e) {

        logger.error("Exception in listTags():", e);
    
        return "input";
    }
}

The code now works when running in an actual servlet container and also through the mock container via the JUnit tests.

One last note, my new StrutsTestCase tests ran successfully through the Eclipse IDE but were failing when run through ANT outside of Eclipse.  I fixed this by adding the Tomcat jars to the Classpath for the Ant build.xml.

Wednesday, April 13, 2011

Hibernate - Part 4 - Testing persistence code with JUnit

I'd like to preface this post by saying this is not intended to be a best practice for testing Hibernate related application code.  I'd just like to show the methodology I'm using at the moment and discuss a few of the call outs I've found on this topic.  Of course, reader input and suggestions are always encouraged so please feel free to fire away.

In a previous post, I discussed the Hibernate mappings file and Ant tasks I'm using to create my Java entity classes and database tables.  I've since created some classes that wrap the CRUD functions for these entities.  I'll refer to these as my persistence classes. Of course these classes use the Hibernate framework (Transaction, Session, Query) and also have a little logic for dealing with the underlying relationship between the entities.

So now I need to test the code.  Yes I know, ideally I'd have written the tests before writing my persistence classes.  :)  I'm using JUnit for unit testing and since both JUnit and Hibernate are quite popular I figured I could quickly locate some online examples of using the two together.  Well, here's where things get a little complicated, or should I say controversial...

First off, I should probably refer to the testing of my persistence classes as integration testing and not unit testing.  As this Stack Overflow post explains, a unit test "should be a stand-alone test which is not related to other resources" and the integration test is "similar to unit tests but with external resources (db, disk access)".

Putting aside the semantics, what's the best way to use JUnit to test your Hibernate related code?  Here are some of the suggestions I've found:
  • Don't do a straight test of Hibernate related code with JUnit, use Spring instead.  Spring has a testing module for writing unit and integration tests.
  • Mock the Hibernate layer by using a mocking framework like JMock.  This enables you to focus your unit test on your code and removes any external frameworks (ie. Hibernate) from the test.
  • Use JUnit extension DbUnit to put your database into a known state before test runs.
  • Use an embedded, in-memory, database like HSQL for your testing.  This removes the reliance on your external full-fledged RDMS.
I'm eager to use Spring but it's not going to happen with this project or at least this phase of the project.  I'd also like to try the mocking or DbUnit approach, and I may do so but it won't happen until later either.

For reference, here's a couple of forum posts where JUnit and Hibernate are discussed:

For now, I'm going against better judgement and testing my persistence code with straight JUnit tests against my MySQL database.  I'll test the CRUD functions of my persistence classes and leave it at that.

I've created a JUnit test class for each of my persistence classes.  Rather than creating a Hibernate SessionFactory with each test method, I'll create it once in the JUnit @BeforeClass method and close it in the @AfterClass method.  Here's what it looks like along with one of the test methods:
    @BeforeClass
    public static void oneTimeSetup() throws Exception  {
        logger.debug("Entering oneTimeSetup()");
       
        // A SessionFactory is set up once for an application
        sessionFactory = new Configuration()
                .configure() // configures settings from hibernate.cfg.xml
                .buildSessionFactory();
    }
   
    @AfterClass
    public static void oneTimeTearDown() {
        logger.debug("Entering oneTimeTearDown()");
       
        if ( sessionFactory != null ) {
            sessionFactory.close();
        }
    }
   
    @Test
    public void testCreateTag() {
        logger.debug("Enter testCreateTag()");
       
        // create new Tag object
        Tag tag = new Tag("tag1");
       
        TagPersister tagPersister = new TagPersister();
       
        // Ask for a session using the JDBC information we've configured
        Session session = sessionFactory.openSession();
       
        assertTrue("Error while creating new Tag", tagPersister.createTag(tag, session));
    }
What do you think?  Reader ideas and suggestions are encouraged and appreciated.

    Thursday, April 7, 2011

    Getting started with JUnit and Eclipse

    Over the years I've done load testing and user acceptance testing but this is the first time I've done any serious unit testing. I'm be using JUnit 4.x and trying my best to stick test-driven development.

    Everyone learns in different ways, some are book-learners and others like to dive right in and get their hands dirty.  I'd like to think I take a hybrid approach but I'm always thankful for a nice tutorial.  I definitely recommend the Eclipse and Java for Total Beginners video tutorial.  Sure it's geared for true Java and Eclipse beginners but it covers JUnit and test-driven development in some clear and concise detail.

    The tutorial doesn't include using Ant to run your JUnit tests.  Here's the code I am currently using in my Ant build.xml for invoking the JUnit tests in my project.

    <target name="junit" depends="compile, jar">
        <junit showOutput="true" printsummary="on" fork="true" haltonfailure="true" dir="${basedir}">
            <classpath refid="project.classpath" />
            <formatter type="xml" />
            <batchtest todir="${output.dir}">
                <fileset dir="${test.dir}">
                    <include name="**/*Test*.java" />
                </fileset>
            </batchtest>
        </junit>
    </target>