Anthony
Anthony

Reputation: 35988

How can I unit test this method in java?

I'm working with the Struts2 framework and would like to unit test the execute method below:

public String execute() {
    setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));
    setUserPrincipal(); //fetches attribute from request and stores it in a var
    setGroupValue(); //
    setResults(getMyDao().getReportResults(getActionValue(), getTabName());
    setFirstResultSet((List) getResults()[0]);
    setSecondResultSet((List) getResults()[1]);
    return SUCCESS;
}

As you can see most of the logic is database related. So how would I go about unit testing this functionality? I would like to unit test by mocking a HTTPServletRequest with few request variables inside it.

My questions are:

I'd appreciate any book/article that shows how to really accomplish this.

Upvotes: 3

Views: 600

Answers (3)

Jeshurun
Jeshurun

Reputation: 23186

  1. Instead of simply mocking the HTTPServletRequest, how about mocking an actual automated targeted request to the application itself? Check out Selenium which lets you do just that.

  2. For testing DAOs (integration testing), you could create your databases in memory using HSQLDB, which will allow you to create / delete objects from your tests, and making sure they are persisted / retrieved properly. The advantage with HSQLDB is that your tests will run much quicker than they will with an actual database. When the time comes to commit your code, you could run the tests against your actual database. Usually, you would setup different run configurations in your IDE to facilitate this.

  3. The easiest way to make your injected daos available to your tests is to let your unit test classes extend AbstractJUnit4SpringContextTests. You could then use the @ContextConfiguration annotation to point to multiple xml application context files, or if you use annotation based configuration, point it to your context file which has the <context:annotation-config /> declaration in it.

Upvotes: 0

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340923

The code you have shown us is not enough to fully answer your question.

Line by line

setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));

This is the hardest line since it uses static method. We would need to see how ApplicationInitializer works. In ideal world the getApplicationContext() method should return mock of ApplicationContext. This mock in turns should return MyDAO when getBean("MyDAO"). is perfectly capable of handling this, as well as all other mocking frameworks.


setUserPrincipal(); //fetches attribute from request and stores it in a var

Where does the request come from? Is it injected to action class? If so, simply inject mocked request object, e.g. MockHttpServletRequest.


setGroupValue(); //

Same as above? Please provide more details, what this method actually does?


setResults(getMyDao().getReportResults(getActionValue(), getTabName());

Your previously created mock should return something when getReportResults() is called with given arguments.


setFirstResultSet((List) getResults()[0]);
setSecondResultSet((List) getResults()[1]);

I guess methods below set some field on the action class. Because you have full control over what was returned from mocked getReportResults(), this is not a problem.


return SUCCESS;

You can assert whether SUCCESS was the result of execution.


Now in general

How can I fake/mock a request variable as if its coming from a browser

See above, there is a mock built-in in Spring.

Should my unit test be calling the actual DAO and making sure that the data is coming back?

If your unit test calls real DAO, it is no longer unit test. It is an integration test.

If so, how can I call the DAO from unit test since the DAO is tied to the server since jndi pool settings reside on the application server.

This means you are doing integration testing. In that case you should use in-memory database like so you can still run the test on server. You must somehow configure your application to fetch DataSource from different place.


Final note

In essence you should inject mocks of everything to your Struts action class. You can tell mocks to return any value upon calling. Then, after calling execute(), you can verify given methods were called, fields set and result value is correct. Consider splitting this to several tests.


Code review

  • Struts 2 integrates perfectly with Spring. If you take advantage of that functionality Spring container will automatically inject MyDAO to your action class. The first line becomes obsolete.

Upvotes: 6

JB Nizet
JB Nizet

Reputation: 692053

This code is hard to unit test because instead of using Spring as intended (i.e. as a dependency injection framework), you use it as a factory. Dependency injection is precisely used to avoid this kind of bean lookup you're doing, which is hard to test. The DAO should be injected into your object. That way, you could inject a mock DAO when unit testing your object.

Also, this logic is not database-related at all. The DAO contains the database-related logic. This action uses the DAO, and the DAO is thus another unit (which should be tested in its own unit test). You should thus inject a mock DAO to unit test this method.

Finally, this method doesn't use HttpServletRequest (at least not directly), so I don't understand why you would need to use a fake request. You could mock the setXxx methods which use the request.

Upvotes: 1

Related Questions