How to mock classes instantiated as local variables - java

I'm writing tests for a business method that invokes some DAO classes to perform operations over a database.
This method, firstly retrieves a JDBC connection from a DataSource object, The same connection is passed to all DAO instances, so I can use it to control the transaction. So, if everything works properly, I must invoke commit() over the connection object.
I would like to test if the commit() is invoked, so I've thought to create an expectation (I'm using JMock) that checks that. But since the Connection class isn't a direct neighbour from my Business class, I don't know how to do this.
Someone knows how to overcome this? There is some JMock facility for this, or some alternative design that allows to overcome this?
Thanks

You need to mock DataSource and Connection so that your mock DataSource returns your mock Connection. And yes, this kind of thing ends up becoming a real pain...

It's hard for me to tell from your description exactly how your classes are composed, but the DataSource should be injected into your DAO class, either thru it's constructor or a setDataSource() method.
This would allow you to test the DAO in isolation, and allow you to construct the mock DataSource in your unit test and pass it to the DAO being tested.

Refactor so that the Connection is injected into the Dao and the Dao injected into the business class. You can then mock the Dao and / or the Connection. You can easily write your own mock that extends the Connection and overrides connect() to set a boolean that you later retrieve via a method that write such as wasConnectCalled().

I would definitely recommend that you use spring-jdbc instead of trying to write this kind of code yourself. This will make sure that the connection, statement and resultset are closed correctly. Spring also has excellent transaction management so you simply don't have to worry about this.
For example take a look at this typical update statement using spring-jdbc:
public void updateName(int id, String name) {
getJdbcTemplate().update(
"update mytable set name = ? where id = ?",
new Object[] {name, new Integer(id)});
}

Make the bussines class retrieve the local variables from a global/static object factory. That way you could put the factory in test mode and make it return mock objects instead of real ones.
That should make it.

#Paul seconded. And once you've split management of the connection out, you can write the rest of the behaviour in a callback that you pass into the thing that owns the connection -- like a UnitOfWork. The connection owner handles the transaction around, and passes the connection to, the UnitOfWork. Transactions in one place -- easy to test, UnitOfWork in another place, tested with a mock connection.

Related

Testing JDBC methods, including transactional aspect and connection closeds

I would like to define tests for JDBC methods for educational purposes. In particular, in addition to test whether the JDBC methods have the functionality required (I have seen that there are solutions such as DBUnit, etc), I would also like to check whether the methods verify specific requirements:
- if they consider transactional issues when modifying (setAutocommit(false)/commit/rollback)
- if they close the connection,
- etc.
I have not found any testing solution that checks whether spectific methods are invoked (methods such as the previous ones). The only thing that comes to my mind is trying to use a testing solution (such as DBUnit) together with AOP (for example AspectJ) for advising whether such methods are invoked.
Any other idea?
Thank you!
There are mainly three ways to do what you want to achieve:
Mocking JDBC
Popular choices are mockito or jmock. Using jmock, for instance, you can write things like:
Mockery m = new Mockery();
Connection c = m.mock(Connection.class);
PreparedStatement s = m.mock(PreparedStatement.class);
m.checking(new Expectations() {{
oneOf(connection).prepareStatement("test"); will(returnValue(s));
oneOf(s).setFetchSize(10);
oneOf(s).execute();
oneOf(s).getUpdateCount();
oneOf(s).getWarnings();
oneOf(s).close();
}});
And then:
// Example code under test:
try (PreparedStatement ps = c.prepareStatement("test")) {
ps.setFetchSize(10);
ps.execute();
ps.getUpdateCount();
ps.getWarnings();
}
// Finally, check if everything was called as expected.
m.assertIsSatisfied();
Implementing JDBC
Mocking APIs help you provide a mock implementation very easily, but you may wish to do much more than just mock the driver. In that case, you could actually implement JDBC:
class MyConnection implements Connection {
final Connection delegate;
public MyConnection(Connection delegate) {
this.delegate = delegate;
}
// ...
}
In this case, you can now intercept any method call and start collecting statistics and make assertions inside of the desired methods without modifying the underlying database interaction, as all JDBC calls will be delegated to the actual driver.
Many libraries, including e.g. jOOQ, ship with utilities for creating such proxying JDBC objects, see e.g. jOOQ's DefaultConnection. jOOQ also has an entire mock JDBC implementation, which can be seen in these articles:
https://blog.jooq.org/2018/04/10/mocking-jdbc-using-a-set-of-sql-string-result-pairs/
https://blog.jooq.org/2013/02/20/easy-mocking-of-your-database/
But I'm not sure if that's what you're after.
(Disclaimer: I work for the company behind jOOQ)
Using AOP
By using a tool like Javassist, you can intercept certain method calls such as the desired JDBC method calls, and run additional logic before or after the actual call. This works in the same way as the previous approach of implementing JDBC, except you don't have to modify the application under test, so it is the least intrusive and simplest approach for simple validation tasks.

How to close a mocked connection object in easymock

I have used easymock for creating a java.sql.Connection mock object(con). My doubt is
Should i use con=null for cleanup or
con.close() for cleanup ?
In my opinion it should be the first one but still wanted to clear my doubts.
It is a mock object so it will not be creating actual connection to the database. So, the first one should suffice in my opinion. If you call conn.close(), you will have to mock it anyways.

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:
How can I fake/mock a request variable as if its coming from a browser
Should my unit test be calling the actual DAO and making sure that the data is coming back?
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.
I'd appreciate any book/article that shows how to really accomplish this.
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"). mockito 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 h2 so you can still run the test on ci 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.
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.
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.
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.
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.

Help writing JUnit for JDBC

I created one class,in which i am inserting values into SQL as follows:
public class ABC{
some code here..........
...............
public void insertUsers(String firstName,String lastName,String location){
pre.setString(1,firstName);
I created test class for this class.
I want to write test case for this method insertUsers(),using assert statement.
how to write assert statement for above method.
When doing unit testing one should avoid accessing external resources such as databases, filesystems, network etc. This is to keep the tests in memory (fast), but also isolated from external failures. You only want to test a specific part of some functionality in e.g. a class, nothing else.
What this means for you is that the conn variable (I assume is the db connection) needs to be mocked out. You can do this easily with something like dependency injection, which means you pass in things into your class when constructing it. In this case you would pass in an interface which has the necessary functions conn uses.
Then in production you pass in the real db connection object while in test you pass in a mock which you control. Hence, you can then check that ABC calls and does what you expect it to do with conn. The same goes for pre you're using.
You can see it like this: I would like to test class ABC, and in order to do that I need to see how it uses pre and conn, so I replace those with my own test implementations I can check after doing something with ABC.
In order to specifically help you with what you're doing you need to show what pre is and tell us what you intend to test.
Well if you really want to test updating your database you can do that. Usually people follow one of the below two approaches -
Use Spring AbstractTransactionalDataSourceSpringContextTests This allows you to add any values to the database and then spring will take care and revert the values that you have inserted.
Use a seperate database Just for your JUnit tests. You really dont need anything heavy. You can use something like the HSQLDB which is really a lightweight java database. This will allow you to have separate test data from your production/QA database.
After the above is done(and you have run the insert statement) simply run select statement from your JUnit to get the data and then compare the previous data with the actual data.
A couple of remarks.
I'd use the standard assert during development only. It will check a condition and throw a runtime exception, if the condition evaluates to false.
If you expect illegal arguments, than it's much better to add some "normal" code to the method to handle those values or throw an IllegalArgumenException and write log entry.
Do not close the connection in this method! Do it only when you open/create the connection in the very same method. In larger applications you won't be able find out who closed the connection after a while. If the caller of insertUsers opened the connection, the caller should close it itself!
(more help possible if you tell us what exactly you want to test - the method parameters or if the insert was a success)
I wouldnt test the insertion of the data to the database, actually its not performant to access database during unittesting, this can be covered threw automated functional GUI testing tools of your application.
what you may want to test is the generation of the expected queries, this can realised if you seperate the geenration and the execution of the statements, you will be able to compare generated statements with expected ones without having to access you database from the unitest.

AOP for third-party classes

I have used AOP within spring with no real problems, mainly for transaction management, for which it works a charm.
My question is this... the only examples I've seen for AOP so far is to pointcut a class that you have created yourself. Is it possible to pointcut a class within a third party library, for example a database connection class. The context is that I wish to create some logs and gather information when an oracle data source executes a call to the database, which is unfortunately contained within a stack of oracle class files. How would you pointcut this class/method when the SQL is executed?
I think this will work:
Let Spring be responsible for initializing your DataSource
Apply an aspect against the getConnection() method on your DataSource
In your advice, wrap the returned Connection in a new class ("LoggingConnection") which implements Connection and delegates all methods to the "real" wrapped Connection (I believe this is the Decorator pattern)
Add whatever logging code you need to the "LoggingConnection" class
Bear in mind that this approach creates a proxy of the original DataSource and delegates to it for each method call. In the context of a database operation this shouldn't create a lot of additional overhead. You will want to be extremely careful what your code is doing, lest it throw exceptions and prevent Connections from behaving appropriately. Perhaps use try/catch/finally and put the call that delegates to the "real" Connection in your finally block.
Another totally different approach would be to use AspectJ and do load-time weaving. That way you can decorate the class with new functionality as soon as the ClassLoader loads it.

Categories

Resources