JAXRS + JerseyTest testing a REST Service - java

I've created a Rest service with four methods, GET,POST,UPDATE and DELETE.
These methods make connections to a Database to retrieve and store data.
Now I want to test each method. I've used the Jersey Test Framework for this. And it is working as long as I remove the code what actually makes the call to the database. When I leave the code that makes the call to the database it throws an exception that it could not connect to the database.
EDIT: I have done some research and used dependancy injection. The db calls are moved to a separate class but I'm still doing something wrong.
DatabaseResults. In this class the call to the DB is made.
public class DatabaseResults {
private final String getQuery = "SELECT * FROM movies";
private Connection connection = null;
private PreparedStatement pstmt = null;
private final ArrayList<Movie> jsonList = new ArrayList<>();
public JSONObject getAllMovies() throws SQLException {
try {
ComboPooledDataSource dataSource = DatabaseUtility.getDataSource();
connection = dataSource.getConnection();
pstmt = connection.prepareStatement(getQuery);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
jsonList.add(new Movie(rs.getString(1), rs.getString(2), rs.getString(4), rs.getString(3)));
}
} catch (SQLException ex) {
System.out.println(ex);
System.out.println("Could not retrieve a connection");
connection.rollback();
} finally {
connection.close();
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("movies", jsonList);
return jsonObject;
}
}
MoviesResource that contains the REST methods
#Path("movies")
public class MoviesResource {
....
private DatabaseResults dbResults = null;
public MoviesResource() {
this(new DatabaseResults());
}
MoviesResource(DatabaseResults dbr){
this.dbResults = dbr;
}
....
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllMovies() throws JSONException, SQLException {
return Response.status(200).entity(dbResults.getAllMovies().toString()).build();
}
The Test class
#RunWith(MockitoJUnit44Runner.class)
public class MovieResourceTest extends JerseyTest {
JSONObject jsonObject = new JSONObject();
#Mock
DatabaseResults dbr;
#Before
public void setup() throws SQLException{
jsonObject.put("id", "hello");
when(dbr.getAllMovies()).thenReturn(jsonObject);
}
Client client = ClientBuilder.newClient();
WebTarget target = client
.target("http://localhost:9998/RestServiceMovies/resources");
#Override
protected Application configure() {
return new ResourceConfig(MoviesResource.class);
}
#Test
public void getAllMoviesTest() throws SQLException {
String responseGetAllMovies = target("/movies").request().get(String.class);
Assert.assertTrue("hello".equals(responseGetAllMovies));
}
At this moment I can run the tests but still when I test the getAllMovies() method it makes a call to the real database instead of returning the jsonObject.
I have the feeling that a connection is missing between the mock object and the constructor from the MovieResource class?

When you register your resource as a class
new ResourceConfig(MoviesResource.class)
you are telling Jersey to create the instance. If you don't have any DI configured, it will just call the no-arg constructor. In your no-arg constructor, you are just creating the service yourself. It knows nothing about your mock.
What you should do instead is register the resource class as an instance. That way you can pass the mock to the constructor.
MockitoAnnotations.initMocks(this);
return new ResourceConfig()
.register(new MoviesResource(dbr));
Don't use the Mockito runner. Instead use the MockitoAnnotations.initMocks method. That way you control when the #Mocks are injected. If you use the runner, the injection will not happen in time, as the the configure method is called by the framework before the Mockito injection happens.

Related

Test CRUD Operation while mocking static PreparedStatement method within the method

My original CRUD Method generates a Prepared Statement and sets the strings based on the parameters given.
public class StatementUtility {
...
public static PreparedStatement getFoo(String bar, Connection conn) {
String query = "SELECT Foo FROM BarTable WHERE Bar = ?";
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(query);
pstmt.setString(1, bar);
}
catch (SQLException e) {
..
}
return pstmt;
}
...
}
In this Statement the Database which I use is set. I created however a TestDB within my MySQL Server where I would like to test a delete Method:
public static String deleteFoo(List<String> input) {
Connection conn = driver.connectCustomerDB(input);
try(PreparedStatement pstmt = StatementUtility.getFoo(String someString, conn)) {
...
}
}
Here is my Test so far
#RunWith(PowerMockRunner.class)
#PrepareForTest(StatementUtility.class)
public class DBConnectionBTBAdminTest {
#Test
public void deleteTest() {
List<String> testInput = new ArrayList<>();
testInput.add("hello");
testInput.add("World");
Driver driver = new Driver();
Connection conn = driver.connectCustomerDB(testInput);
String query = "FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar";
try {
//try mocking the Method within
BDDMockito.given(StatementUtility.getFoo(ArgumentMatchers.anyString(), ArgumentMatchers.anyString(), any(Connection.class))).willReturn(conn.prepareStatement(stringBuilder.toString()));
//call the method I want to test
SomeClass.deleteCategory(testInput, emptyArray);
...
} catch (SQLException e) {
...
}
}
}
The error that I get is a Nullpointer Exception in the Method where I create the PreparedStatement originally, but that is not the point as I do not want to get into this Method at all, but stub it.
I also tried using Mockito instead of BDDMockito (see here: https://stackoverflow.com/a/21116014/8830232)
and using the real values instead of ArgumentMatchers.*
I also tried some other stuff like mocking the Connection
Currently I am using JUnit#4.12, Mockito#2.13.0, powermock#1.7.1
EDIT:
For #glytching answer to work I had to downgrade mockito from 2.x to 1.x. >Dont forget to adjust powermock dependencies in that case
In addition to #PrepareForTest(StatementUtility.class) (which tells PowerMock to prepare this class for testing) you have to enable static mocking for all methods of StatementUtility. You do this by invoking ...
PowerMockito.mockStatic(StatementUtility.class);
... in your test before you attempt to set any expectations on that mock.
For example:
#RunWith(PowerMockRunner.class)
#PrepareForTest(StatementUtility.class)
public class DBConnectionBTBAdminTest {
#Test
public void deleteTest() {
PowerMockito.mockStatic(StatementUtility.class);
List<String> testInput = new ArrayList<>();
testInput.add("hello");
testInput.add("World");
Driver driver = new Driver();
Connection conn = driver.connectCustomerDB(testInput);
String query = "FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar";
try {
BDDMockito.given(StatementUtility.getFoo(...)).willReturn(...);
...
} catch (SQLException e) {
...
}
}
}

Trying to Understand Java Dependency Injection with Example

I'm trying to create a database connection library to be used in all my apps. I want to make sure that this library is fully unit tested and so i'm trying to use dependency injection.
I have this class which i want to ensure is tested:
public class ConnectionFactory {
private String dataSourceName;
public ConnectionFactory(String dataSourceName) {
if(dataSourceName == null) {
throw new NullPointerException("dataSourceName can't be null");
}
this.dataSourceName = dataSourceName;
}
public Connection getConnection() throws SQLException {
Connection connection = getDataSource(dataSourceName).getConnection();
if(connection != null) {
return connection;
}
...
}
// Get a datasource object
private DataSource getDataSource(String dataSourceName) {
...
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:comp/env/" + dataSourceName);
} catch (NamingException e) {
...
}
return dataSource;
}
}
I want to be able to simply call this class from all my apps with something as simple as this:
public class MyApp {
public static void main(string[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory("jdbc/myDataSource");
Connection connection = connectionFactory.getConnection();
}
}
I've started writing unit tests for this ConnectionFactory, but quickly realized that with my current code I can't mock the DataSource object so it's trying to actually connect to a real data source.
#RunWith(Nested.class)
public class ConnectionFactoryTest {
public class Constructor {
#Test
public void shouldThrowNullPointerIfParamIsNull() {
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> { new ConnectionFactory(null); })
.withMessage("dataSourceName can't be null");
}
}
public class GetConnection {
public class WithDataSourceAvailable {
#Test
public void shouldErrorIfParamIsNull() {
ConnectionFactory connectionFactory = new ConnectionFactory("jdbc/myDataSource"); // <-- This is going to fail b/c it's trying to actually fetch a real data source
}
}
}
}
How can I properly use Dependency Injection so that I can write unit tests that don't actually try to connect to a data source?
Take a look at Mockito I find it easy to use for this type of mocking.

DB design without passing around jdbc

I have a db design issue that I am facing with one of my projects. I am trying to implement a service and part of that service is a db layer. It is setup such that I have helper classes that perform get/update methods to the database and a layer on top of them that is a janitor. For ex:
public class GetStudentDBHelper {
public List<Student> get(List<Integer> ids) {
Conn getConnection...
// run sql query and construct returning Student objects
}
public List<Student> get(List<Classroom> byClassroom) {
// get all students in passed in classrooms
// run sql query and construct returning Student objects
}
}
public class StudentJanitor {
public GetStudentDBHelper getStudentDBHelper;
public UpdateStudentDBHelper updateStudentDBHelper;
public UpdateClassroomDBHelper updateClassroomDBHelper;
public List<Student> getStudents(List<Integer> ids) {
return getStudentDBHelper.get(ids);
}
public void saveStudents(List<Students> students, int classRoomid) {
Connection conn = Pool.getConnection(); // assume this gives a jdbc
conn.autocommit(false);
try {
try
{
updateStudentDBHelper.saveForClassroom(students, classRoomid, conn);
updateClassroomDBHelper.markUpdated(classRoomid, conn);
conn.commit();
}
catch
{
throw new MyCustomException(ErrorCode.Student);
}
}
catch (SQLException c)
{
conn.rollback();
}
finally {
conn.close();
}
}
public class ClassroomJanitor{
public void saveClassRoon(List<Classrooms> classrooms) {
Connection conn = Pool.getConnection()// assume this gives a jdbc
conn.autocommit(false);
try {
try {
updateClassroomDBHelper.save(classrooms, conn);
updateStudentDBHelper.save(classrooms.stream().map(Classroom::getStudents).collect(Collections.toList()), conn);
conn.commit();
}
catch {
throw new MyCustomException(ErrorCode.ClassRoom);
}
}
catch (SQLException c)
{
conn.rollback();
}
finally {
conn.close();
}
}...
public class GetClassroomDBHelper{}...
public class UpdateClassroomDBHelper{}...
The update db classes all compose multiple other updators in case they need to update values in other tables (ie. saving a student means I have to touch a classroom table in which a student belongs to update its last updated time for instance).
The issue I am having is for the update db classes, I have to pass in a connection from my Janitor class if i am touching multiple tables in order to have transactions and their rollback capabilities. See above for what I mean. Is there a better way to do this? This type of try, catch, pass in conn to db helpers, will have to be done for any multi transaction operation in my janitors.
In short, you can see that the code is generally like this duplicated across multiple methods:
Connection conn = Pool.getConnection()// assume this gives a jdbc
conn.autocommit(false);
try {
try {
//do some business logic requiring Connection conn
}
catch {
throw new MyCustomException(ErrorCode);
}
}
catch (SQLException c)
{
conn.rollback();
}
finally {
conn.close();
}
Whenever you have a code sequence that is duplicated but it only differs in some parts you can use a template method.
In your case I would introduce a TransactionTemplate class and use a callback interface for the parts that are different. E.g.
public class TransactionTemplate {
private DataSource dataSource;
public TransactionTemplate(DataSource dataSource) {
this.dataSource = Objects.requireNonNull(dataSource);
}
public <T> T execute(TransactionCallback<T> transactionCallback) throws Exception {
Connection conn = dataSource.getConnection();// assume this gives a jdbc
try {
conn.setAutoCommit(false);
T result = transactionCallback.doInTransaction(conn);
conn.commit();
return result;
} catch (Exception e) {
conn.rollback();
throw e;
} finally {
conn.close();
}
}
}
The callback interface would look like this
public interface TransactionCallback<T> {
public T doInTransaction(Connection conn) throws Exception;
}
As you can see the TransactionTemplate manages the transaction while the TransactionCallback implements the logic that must be done in one transaction.
Your client code will then look like this
public class StudentJanitor {
private TransactionTemplate transactionTemplate;
StudentJanitor(DataSource dataSource) {
transactionTemplate = new TransactionTemplate(dataSource);
}
public void saveStudents(List<Students> students, int classRoomid) {
SaveStudentsTransaction saveStudentsTransaction = new SaveStudentsTransaction(students, classRoomid);
transactionTemplate.execute(saveStudentsTransaction);
}
}
and the logic is placed in the TransactionCallback
public class SaveStudentsTransaction implements TransactionCallback<Void> {
public GetStudentDBHelper getStudentDBHelper;
public UpdateStudentDBHelper updateStudentDBHelper;
public UpdateClassroomDBHelper updateClassroomDBHelper;
private List<Students> students;
private int classRoomid;
public SaveStudentsTransaction(List<Students> students, int classRoomid) {
this.students = students;
this.classRoomid = classRoomid;
}
#Override
public Void doInTransaction(Connection conn) throws Exception {
try
{
updateStudentDBHelper.saveForClassroom(students, classRoomid, conn);
updateClassroomDBHelper.markUpdated(classRoomid, conn);
conn.commit();
}
catch
{
throw new MyCustomException(ErrorCode.Student);
}
return null;
}
}
Two main concerns you are currently facing are the boiler plate code for repetitive tasks related to connection (get/execute/close etc)
and infrastructure for getting the same connection across method boundaries. The first is typically solved using Template pattern and the latter
using Threadlocal variables to pass around appropriate connection across methods. These type of concerns have been solved in Java world long ago but
will require you to rely on framework like Spring (JDBC template) etc which have this feature from last decade or so or you would need to roll out stripped
down version of this infrastructure. If you are interested in latter then you can take hint from similar attmepts shared on Github like this.

The Jdbc Template Mocking In java

I am trying to mock the dao class but I am not able to mock the dao class, it throws null pointer exception (in the dao class I am using spring jdbc template). I tired to mock the jdbc template also but still it returns jdbc template as null.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ LocationAppDAO.class, BeanPropertyRowMapper.class })
public class CopyOfGeoLocationAppTest {
#Autowired
private ApplicationContext applicationContext;
#Test
#SuppressWarnings({ "unchecked" })
public void testJdbcTemplateforDbase() throws Exception {
// LocationAppDAO locationAppdao= new LocationAppDAO();
String queryWgs84 = "SELECT * FROM location_wgs84 where latitude=" + 0
+ " AND longitude=" + 0;
LocationAppDAO locationAppDaoMock= EasyMock.createMock(LocationAppDAO.class);
JdbcTemplate jdbcTemplateMock = EasyMock.createMock(JdbcTemplate.class);
BeanPropertyRowMapper<Location_wgs84> beanPropertyRowMapperMock = EasyMock
.createMock(BeanPropertyRowMapper.class);
EasyMock.replay(beanPropertyRowMapperMock);
// mocking location
Location_wgs84 location_wgs84mock = EasyMock
.createMock(Location_wgs84.class);
location_wgs84mock.setLatitude(0);
location_wgs84mock.setLongitude(0);
EasyMock.replay(location_wgs84mock);
PowerMock.expectNew(BeanPropertyRowMapper.class).andReturn(
beanPropertyRowMapperMock);
PowerMock.replayAll();
ArrayList<Location_wgs84> arrayList = new ArrayList<Location_wgs84>();
Location_wgs84 location1 = new Location_wgs84();
location1.setLatitude(1);
location1.setLongitude(1);
arrayList.add(location1);
Location_wgs84 location2 = new Location_wgs84();
location2.setLatitude(2);
location2.setLongitude(2);
arrayList.add(location2);
Location_wgs84 location3 = new Location_wgs84();
location3.setLatitude(3);
location3.setLongitude(3);
arrayList.add(location3);
EasyMock.expect(
jdbcTemplateMock.query(queryWgs84, beanPropertyRowMapperMock))
.andStubAnswer(new IAnswer<List<Location_wgs84>>() {
#Override
public List<Location_wgs84> answer() throws Throwable {
return arrayList;
};
});
EasyMock.replay(jdbcTemplateMock);
EasyMock.expect(
locationAppDaoMock.location_wgs84Query(0,0))
.andStubAnswer(new IAnswer<List<Location_wgs84>>() {
#Override
public List<Location_wgs84> answer() throws Throwable {
return arrayList;
};
});
EasyMock.replay(locationAppDaoMock);
LocationAppDAO locationAppdao= new LocationAppDAO();
ReflectionTestUtils.setField(locationAppdao, "jdbcTemplate", jdbcTemplateMock);
List<Location_wgs84> arrayListResult = locationAppdao.location_wgs84Query(0, 0);
assertEquals(3.0, arrayListResult.get(2).getLatitude(), 0);
EasyMock.verify(jdbcTemplateMock);
}
}
Instead of using mocking libraries, I often use H2 database. I set up an in memory database with a DDL that allows me to verify that my application is making the right changes to the underlying tables and/or stored procedures, without having to lock my tests to the specifics of the database access library.
All you need to do is provide a connection string when running tests, similar to the one below. It will create the database and run the DDL any time a connection is made.
jdbc:h2:mem:example_database;INIT=RUNSCRIPT FROM 'classpath:db/my-example-database.ddl'

simple restlet login

I am playing with restlet and i want to create a login mechanism that passwords and usernames are store in a MysqlDatabase.
public class zeus extends Application {
#Override
public Restlet createInboundRoot() {
// Δημιουργία του router.
Router router = new Router(getContext());
router.attach("/customers", CustomersResource.class);
ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(), ChallengeScheme.HTTP_BASIC, "login required");
UserVerifier verifier = new UserVerifier();
verifier.verify(identifier, secret); // where do i get the identifier ?
guard.setVerifier(verifier);
guard.setNext(router);
return guard;
}
}
And my user verifier class
public class UserVerifier extends SecretVerifier {
#Override
public boolean verify(String identifier, char[] secret) {
System.out.println(identifier);
System.out.println(secret);
//TODO compare with the Database
return true;
}
}
i cannot find how to get the identifier.
If I correctly understand your question, your problem is how to interact with the database from your Restlet verifier and how make work together within your Restlet application.
The best approach is to define a DAO that implement your database interaction logic. Something like that:
public class SecurityDao {
private DataSource dataSource;
public SecurityDao() {
// Intialize your datasource using DBCP or C3P0
dataSource = new com.mchange.v2.c3p0.ComboPooledDataSource();
dataSource.setDriverClass(MyDriverClass.class);
dataSource.setJdbcUrl("jdbc:mysql://locahost/mydb");
dataSource.setUser("username");
dataSource.setPassword("pwd");
// Don't forget to clean the pool when Restlet application stop
// with ComboPooledDataSource#close method
}
public boolean hasUserPassword(String user, String password) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// Some SQL request like that
ps = conn.prepareStatement("select * from <MYTABLE> where USER = ? and PASSWORD = ?");
ps.setString(1, user);
ps.setString(2, password);
rs = ps.executeQuery();
return rs.next();
} catch(Exception ex) {
(...)
} finally {
// close rs
// close ps
// close conn
}
}
}
Now we have the DAO implemented, we will instantiate it from the Restlet application class and set it within your verifier:
public class zeus extends Application {
private SecurityDao securityDao;
public zeus() {
securityDao = new SecurityDao();
}
#Override
public Restlet createInboundRoot() {
(...)
UserVerifier verifier = new UserVerifier();
verifier.setSecurityDao(securityDao);
(...)
return guard;
}
}
You need now to adapt a bit your verifier as described below:
public class UserVerifier extends SecretVerifier {
private SecurityDao securityDao;
public void setSecurityDao(SecurityDao securityDao) {
this.securityDao = securityDao;
}
public boolean verify(String identifier, char[] secret) {
System.out.println(identifier);
System.out.println(secret);
return securityDao.hasUserPassword(identifier, new String(secret));
return true;
}
}
In fact, the method createInboundRoot of the Restlet application initializes the routing. This is done once when the application starts ie when the first request is done. Then when an HTTP request will be received, Restlet automatically calls the verifier with security hints present in this request. You haven't to explicitly call the verify method of the verifier, the Restlet framework will do that...
Hope it helps you,
Thierry

Categories

Resources