Mock Oracle CallableStatement.getCursor() - java

I'm dealing with an Oracle 10g database and the following stored procedure is provided:
procedure get_synopsis (
p_id in my_schema.products.p_id%type,
p_synopses out sys_refcursor); -- cursor of - synopsis_type, synopsis_text
In my Java code I prepare the statement in this way:
String idForDb = fromIdUrlToIdDb(prodIdUrl);
statement.registerOutParameter(1, OracleTypes.VARCHAR);
statement.setString(1, idForDb );
statement.registerOutParameter(2, OracleTypes.CURSOR);
And I get the data I need in this way:
String defaultSyn, nonDefSyn;
String returnedId = ((OracleCallableStatement)stm).getString(1);
try ( ResultSet synopses = ((OracleCallableStatement)stm).getCursor(2) ){ // p_synopses - cursor of: synopsis_type, synopsis_text
while( synopses!=null && synopses.next() ){
String type = synopses.getString(1) != null ? synopses.getString(1).toUpperCase() : null;
if( type != null ){
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader( synopses.getClob(2).getCharacterStream() );
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
if("DEFAULT".equals(type)){
defaultSyn = sb.toString();
}else if("NONDEFAULT".equals(type)){
nonDefSyn = sb.toString();
}
// ...
}
}
}
In my tests how can I mock (OracleCallableStatement)stm.getCursor(2)?
I'm trying with org.jmock.Mockery but without success:
Mockery mockery_inner = new Mockery();
final ResultSet mocked_resultset = mockery_inner.mock(ResultSet.class);
mockery_inner.checking(new Expectations() {{
allowing(mocked_resultset).getString(1); will(returnValue("TEST_SYNOPSES-TYPE"));
allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooB"));
}});
Mockery mockery = new Mockery();
final CallableStatement statement = mockery.mock(CallableStatement.class);
mockery.checking(new Expectations() {{
allowing(statement).getString(1); will(returnValue("TEST_RETURNED-PROD-ID"));
allowing(statement).getCursor(2); will(returnValue(mocked_resultset)); // cannot find symbol getCursor(int). Location: interface java.sql.CallableStatement
}});
Reason clearly is: cannot find symbol getCursor(int). Location: interface java.sql.CallableStatement.
If I try allowing((OracleCallableStatement)statement).getCursor(2) I get "java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to oracle.jdbc.driver.OracleCallableStatement". Note: OracleCallableStatement is not an interface and thus cannot be mocked with Mockery.
I'm trying to use a "manual" mock but I'm having problems creating an instance..
class MockOracleCallableStatement implements OracleCallableStatement {
ResultSet mocked_resultset;
public MockOracleCallableStatement(){
Mockery mockery_inner = new Mockery();
mocked_resultset = mockery_inner.mock(ResultSet.class);
mockery_inner.checking(new Expectations() {{
allowing(mocked_resultset).getString(1); will(returnValue("DEFAULT")); // will pick value from an array
allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooooooB"));
}});
}
#Override
ResultSet getCursor(int paramIndex) throws SQLException{
return mocked_resultset;
}
#Override
String getString(int paramIndex) throws SQLException{
return "mockedGetString1--test";
}
}

In a nutshell, DON'T.
Mocking JDBC (along with a lot of other things) is a fools errand and will not test the things you think it's testing but will cost you a huge amount of time.
You should really write an integration test that actually goes to your database. This is the only way to verify your database code is correct. If you can, use the exact same version of the database as you do in production, if not use an in-memory database like H2*.
I wrote an article for JAX magazine on this exact subject which will go into much more detail.
Although this has other issues due to compatibility

It seems like I can use Mockito..
OracleCallableStatement oraCSMock = Mockito.mock(OracleCallableStatement.class);
UPDATE:
The method CLOB.getDBAccess(connection) is a static method of the CLOB class and as such cannot be mocked with Mockito.
(You can mock statics with Powermock).
I ended up testing just the 404 case then:
ResultSet mocked_resultset = Mockito.mock(ResultSet.class);
doReturn( null ) // cant' use "DEFAULT" since getClob() will throw npe anyway. Will test just 404 then.
.when(mocked_resultset).getString(1);
doReturn( false )
.when(mocked_resultset).next(); // or just return null in getCursor(2)
OracleCallableStatement statement = Mockito.mock(OracleCallableStatement.class);
doReturn( "testID" )
.when( statement ).getString(1);
doReturn( mocked_resultset )
.when( statement ).getCursor(2);

Related

SQL Update in another class

Thanks for helping me out with my problem.
So I tried to insert a SQL Update using a method in a class named Functions, the main program doesn't give any error, and whenever I use the function, it just don't change anything in the SQL table after refreshing.
Here is my updateSQL method in class Functions :
public static void updateSQL(String sql, String updatenames[])
{
Connection connected = null;
PreparedStatement prepared = null;
connected = connexionmysql.connexionDB();
try
{
prepared = connected.prepareStatement(sql);
for(int i = 1; i < updatenames.length+1 ; i++) {
prepared.setString(i, updatenames[i-1]);
}
prepared.execute();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
And here is how I call this function in my main class :
String datan[] = { inputPASS, type1, inputEMAIL, inputNAME };
Functions.updateSQL("UPDATE users SET userPASS = ? ,userTYPE = ? ,userEMAIL = ? WHERE userNAME = ? ", datan);
I did solve the problem. The functions I did write are working as expected, but the problem was in the way I was calling the method.
Instead of calling the function in a static way, I was calling it in an "usual" way so Eclipse didn't give me any error in that line.

how to String not null check in JUNIT

I am writing unit tests for he below code. but coverage is missing for the below lines of code. I am not sure how can we cover the below lines.My research didnt help.
public DetailsResponse mapRow(ResultSet resultSet, int num) throws SQLException {
DetailsResponse DetailsResponse = new DetailsResponse();
String[] responseElements = null;
String response = resultSet.getString(1);
//coverage missing for below line
if (response != null && response.indexOf(",") != -1) {
responseElements = response.split(",");
}
//coverage missing for below line
if (responseElements != null && responseElements.length > 0) {
//coverage missing for below line
String id = StringUtils.isNotBlank(responseElements[0]) ? responseElements[0].replace("(", "") : "";
The commented lines are missing from the coverage., how can i test them?
Since this is a public method and you are trying to write a unit test, not an integration test, you can simply setup a ResultSet object. In doing so, you can set the object so that both conditions will get covered.
#Test
public void test(){
// SETUP
ResultSet resultSet = // setup ResultSet to return what looks like a comma separated list.
// TEST
DetailsResponse out = service. mapRow(resultSet, someNum);
// VERIFY / ASSERT
// some assert(s) on out
}

Java returning null pointer exception for SQL query that gets passed to JSP

I am working on a school assignment that required us to use SQL statements in Java code as well as use the LIKE operator for a search. In order to properly search I have to get a string from the user, and split the string by any delimiter, and then run the query like so:
SELECT * FROM movies WHERE (movies.title LIKE '%userInput%');
I then return this query in the form of an ArrayList.
Now, when I was testing it out. I originally tested it with no user input, and my query became: SELECT * FROM movies WHERE (movies.title LIKE '%%');. This gave me the correct results.
However when I put a title in there, all of the sudden I get a NullPointerException on this line:
if(title.equals("")) { return "(movies.title LIKE '%%') "; from this section of my code:
public String getSearchString(String title) {
if(title.equals("")) { return "(movies.title LIKE '%%') "; }
String ret = "(";
ArrayList<String> titleArray = Util.splitSearch(title);
for(int i = 0; i < titleArray.size() - 1; ++i) {
String temp = titleArray.get(i);
String stmt = "movies.title LIKE '%" + temp + "%' OR ";
ret += stmt;
}
String temp = "movies.title LIKE '%" + titleArray.get(titleArray.size() - 1) + "%')";
ret += temp;
return ret;
}
This is then called like so:
public List<Movie> listMovies(String title) throws SQLException {
List<Movie> search = new ArrayList<Movie>();
if(null != title && title.isEmpty()) { title = ""; }
ResultSet res = queryMovies(getSearchString(title));
while(res.next()) {
Movie mov = new Movie();
mov.setTitle(res.getString("title"));
search.add(mov);
}
return search;
}
private static queryMovies(String st) throws SQLException {
ResultSet res = null;
try {
PreparedStatement ps = dbcon.prepareStatement(st);
res = ps.executeQuery();
} catch(SQLException e) {
e.printStackTrace();
}
return res;
}
I unfortunately have to do this since I won't know how much a user will enter. And I am also not allowed to use external libraries that make the formatting easier. For reference my Util.splitSearch(...) method looks like this. It should be retrieving anything that is a alphanumeric character and should be splitting on anything that is not alphanumeric:
public static ArrayList<String> splitSearch(String str) {
String[] strArray = str.split("[^a-zA-Z0-9']");
return new ArrayList(Arrays.asList(strArray));
}
What is interesting is when I pass in getSearchString(""); explicitly, I do not get a NullPointerException. It is only when I allows the variable title to be used do I get one. And I still get one when no string is entered.
Am I splitting the String wrong? Am I somehow giving SQL the wrong statement? Any help would be appreciated, as I am very new to this.
the "title" which is passed from input is null, hence you're getting nullpointerexception when you do title.equals("").
Best practices suggest you do a null check like (null != title && title.equals("")).
You can also do "".equals(title)

Getting a null-point exception in Neo4j data retrieval

I have the following code.
GraphDatabaseFactory dbFactory = new GraphDatabaseFactory();
GraphDatabaseService db= dbFactory.newEmbeddedDatabase("C:/Users/shadid/Documents/Neo4j/DB");
ExecutionEngine execEngine = new ExecutionEngine(db, null);
ExecutionResult execResult = execEngine.execute("MATCH (mat:TheMatrix) RETURN mat");
String results = execResult.dumpToString();
System.out.println(results);
I am getting a null point exception. I have tried running the command in the neo4j command line. So the data do exist. I am not quite sure where is the error. Quite a noob in neo4j so could someone please help me out
Here's the error I am getting by the way
Exception in thread "main" java.lang.NullPointerException
at org.neo4j.cypher.internal.CypherCompiler.(CypherCompiler.scala:69)
at org.neo4j.cypher.ExecutionEngine.createCompiler(ExecutionEngine.scala:237)
at org.neo4j.cypher.ExecutionEngine.(ExecutionEngine.scala:64)
at App.Main.main(Main.java:53)
Just found a more intuitive way of doing the same thing and it works yay!!!
try ( Transaction ignored = db.beginTx();
Result result = db.execute( "MATCH (n:TheIronGiant) RETURN n.`title: `" ) )
{
String rows ="";
while ( result.hasNext() )
{
Map<String,Object> row = result.next();
for ( Entry<String,Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
}
rows += "\n";
}
System.out.println(rows);
}
You are using the ExecutionEngine constructor that takes a LogProvider as the second parameter, but passing a null value for it. If you called the single-parameter constructor instead, which does not take a LogProvider, you may not get the exception.
Also, ExecutionEngine class is now deprecated, and you should use GraphDatabaseService.execute() instead.

How to create an oracle.sql.ARRAY object?

This question is related to my original issue How to return an array from Java to PL/SQL ?, but is a more specific.
I have been reading Oracle Database JDBC Developer's Guide and
Creating ARRAY objects
Server-Side Internal Driver
oracle.jdbc.OracleConnection
oracle.jdbc.OracleDriver
but I still fail to write a minimum code where I can create ARRAY using
ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);
as instructed in Creating ARRAY objects.
I'm using Oracle Database JVM.
I have tried following:
Example 1
create or replace type widgets_t is table of varchar2(32767);
/
create or replace and compile java source named "so20j1" as
public class so20j1 {
public void f1() {
String[] elements = new String[]{"foo", "bar", "zoo"};
oracle.sql.ARRAY widgets =
oracle.jdbc.OracleConnection.createARRAY("widgets_t", elements);
}
};
/
show errors java source "so20j1"
Fails with:
Errors for JAVA SOURCE "so20j1":
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 so20j1:4: non-static method
createARRAY(java.lang.String,java.lang.Object) cannot be
referenced from a static context
0/0 1 error
0/0 ^
0/0 oracle.sql.ARRAY widgets =
oracle.jdbc.OracleConnection.createARRAY("widgets_t", elements);
Example 2
create or replace type widgets_t is table of varchar2(32767);
/
create or replace and compile java source named "so20j2" as
public class so20j2 {
public void f1() {
String[] elements = new String[]{"foo", "bar", "zoo"};
oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
java.sql.Connection conn = ora.defaultConnection();
oracle.sql.ARRAY widgets = conn.createARRAY("widgets_t", elements);
}
};
/
show errors java source "so20j2"
Fails with:
Errors for JAVA SOURCE "so20j2":
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 so20j2:6: cannot find symbol
0/0 symbol : method createARRAY(java.lang.String,java.lang.String[])
0/0 1 error
0/0 oracle.sql.ARRAY widgets = conn.createARRAY("widgets_t",
elements);
0/0 ^
0/0 location: interface java.sql.Connection
Disclaimer: I'm not a Java programmer (yet).
You're on the right track with #2, but you can't create an oracle Array from a connection of type java.sql.Connection. It has to be an OracleConnection to be able to use those methods.
oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
java.sql.Connection conn = ora.defaultConnection();
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
oracle.sql.ARRAY widgets = oraConn.createARRAY("widgets_t", elements);
Based on answers of Affe and Chris Mazzola I have succeeded to build two examples that compile in Oracle 11g R2 database.
Example based on Affe's answer
create or replace type widgets_t is table of varchar2(32767);
/
create or replace and compile java source named "so20ja1" as
public class so20ja1 {
public void f1() throws java.sql.SQLException {
String[] elements = new String[]{"foo", "bar", "zoo"};
oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
java.sql.Connection conn = ora.defaultConnection();
oracle.jdbc.OracleConnection oraConn = (oracle.jdbc.OracleConnection)conn;
java.sql.Array widgets = oraConn.createARRAY("widgets_t", elements);
}
};
/
show errors java source "so20ja1"
Example based on Chris Mazzola's answer
create or replace type widgets_t is table of varchar2(32767);
/
create or replace and compile java source named "so20ja2" as
public class so20ja2 {
public void f1() throws java.sql.SQLException {
String[] elements = new String[]{"foo", "bar", "zoo"};
oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
java.sql.Connection conn = ora.defaultConnection();
oracle.sql.ArrayDescriptor desc =
oracle.sql.ArrayDescriptor.createDescriptor("widgets_t", conn);
java.sql.Array widgets = new oracle.sql.ARRAY(desc, conn, elements);
}
};
/
show errors java source "so20ja2"
// array sample (using a stored procedure to sum two or more numbers)
Connection connection = dataSource.getConnection(username,password);
ArrayDescriptor desc =
ArrayDescriptor.createDescriptor(schemaName + "." + arrayType, connection);
// first ? is the array, second ? is the result via out parameter
String sql = "call sum_numbers(?,?)";
CallableStatement cs = connection.prepareCall(sql);
String[] args = {"5","15","25","35"}; // what to sum
Array array = new oracle.sql.ARRAY(desc, connection, args);
cs.setArray(1, array);
cs.registerOutParameter(2, Types.INTEGER);
cs.execute();
int result = cs.getInt(2);
cs.close();
Just to mention that in Java 1.6 you have connection.createArrayOf(..), which is standard.
Map<String, Object> params = new HashMap<>();
params.put("input_to_sp", new ExampleArrayMapper (new String[] { "ABC" }));
Map<String, Object> results = spObject.execute(params);
final List<Object> output = (List<Object>) results.get("po_out_cur");
public class ExampleArrayMapper extends AbstractSqlTypeValue {
private String[] customObject;
public ExampleArrayMapper (String[] customObject) {
this.customObject= customObject;
}
public String getSQlTypeName() throws SQLException {
return "NAME_OF_TYPE_IN_SQL";
}
#Override
protected Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException {
try {
con = dataSource.getConnection().unwrap(OracleConnection.class);
Array reportsArray = ((OracleConnection) con).createOracleArray(SQL_TYPE_NAME, customObject);
return reportsArray;
} finally {
con.close();
}
}
}
Oracle 12.2 version:
oracle.jdbc.OracleArray v_arr ;
String[] v_list ;
v_arr = ((oracle.jdbc.OracleConnection)DriverManager.getConnection("jdbc:default:connection:")).createARRAY ( "T_STRING_ARRAY" , v_list ) ;

Categories