Unit Testing Oracle views - java

I've searched for best practices, tools and libraries to test oracle db views, but did not find much. Some SQL editors have their own built-in ways, there are some libraries for SQL Server and there's http://utplsql.org/ for PL/SQL, which seems to be the closest thing, but I'm not sure if it fits my needs.
Problem statement: we have tons of business logic written as SQL views. Over time this has become very hard to maintain and small changes can cause surprising regressions. (for all the usual reasons).
I would like something that integrates with a standard java build pipeline so that when we deploy any changes to the db objects (which we currently do with liquibase) we can run a full test suite and reduce the risk of regressions.
If a java solution is not possible, then a SQL or PL/SQL one might also be OK.
The first naïve approach I could think of would be something that
creates some test tables with test data
mocks the view that needs to be tested, by replacing the source tables with the test ones
runs a "select *" from the view and compares it with the desired output
drops the test tables and the mocked view
Is there any existing tool/library that does the above?
If not, is there any particular reason why the above approach would not work?
Thanks

Related

How to apply unit test on DAOs in java

I don't know how to apply unit tests on data access layer. I always wonder if the data access layer should be tested. In my company, we have stable database to store unit test data and test data access layer by running data access objects and check the data they get from the stable database.
In order to pass the unit tests, data in the stable database can not be modified anymore. I think there is a better solution to this. If I am not mistaken, the the mock object cannot perform tests on SQL statements and ResultSet mappings.
What is the best way to unit test the DAO? Is there a better way to do this with TDD?
First, by most definitions, "unit" tests do not depend on external systems like a database. You want to create what are called "functional" or "integration" tests. In practice these types of tests will be implemented in the same way as unit tests, using something like Junit, but you should separate them from unit tests, which should run very fast and not break when your database is down or the data has changed.
Second, try to keep most of your business logic out of DAOs and instead put it into a service POJO layer so that you can test biz logic without involving the database.
Next, the ideal way to set up testing for DAOs is to start with an empty database, and load it with test data (often using the DAOs themselves), and then run your DAO tests against a known, and writable, test dataset. If you're fortunate enough to have a read-only database, the stable database approach you outline will work, but most systems are read/write to the database.
Finally, it is valuable to test DAOs. Often the database queries are some of the most fragile parts of your system, and you don't want to wait until they are deployed to production to find out they are breaking.
Strictly speaking, you're writing a functional test. To do this you're going to need a test database of one sort or another. Let's talk about your options.
HSQL/in-memory DB. Small and fast. Trivial to setup and get rolling, and great performance on unit test sized data. The downside is, unless you are deploying using these environments then you risk having your unit test work but actual code fail. It also means you can't use any SQL constructs which are not support in both HSQL and your production DB. This can be mitigated to an extent by using Hibernate or similar. A good way to go if you only have very simple queries.
Mock out the DB calls entirely. Pointless unless you are doing too much heavy lifting in your DAO.
Use a test instance of your production DB. This will give you the best results in terms of accuracy or results. It will let you test to make sure that all your calls work as expected and lets you use non-portable SQL. You can use something like DBUnit to load database data or just use the DAO under test to do it. I would recommend this if you large and nasty queries. Ones with a lot of edge cases, roll-up views and subtle behavior. The downside is that real DBs will incur performance penalties since they'll be doing real work (transactions, index updates, rollback support).
Some comments/suggestions:
The DAO test is aimed at verifying whether the queries fired and the data retrieved are as per the expectations. There should hardly any business logic to test in DAO.
Since the prime objective is test the database interaction, mocking is not going to make it foolproof, specially the edge cases.
In light of this, the approach that you have right now is fair enough. I am not sure why you feel that its not good. A little elaboration will help.
If you are not convenient on using external database, then you can use Java's inbuilt javaDB for this. Please note that there will be overhead of creating the test data first before you run this test.
For JDBC based project, JDBC connection can be mocked, so that tests can be executed without live RDBMS, with each test case isolated (no data conflict).
It allow to verify, persistence code passes proper queries/parameters (e.g. https://github.com/playframework/playframework/blob/master/framework/src/anorm/src/test/scala/anorm/ParameterSpec.scala) and handle JDBC results (parsing/mapping) as expected.
Framework like jOOQ or my framework Acolyte can be used for: https://github.com/cchantep/acolyte .

Best place to put SQL statements in Java

I know there are pros and cons to each approach, but is there a best practice on where to put the SQL statements? I've always put them inside of the Java classes, but I came on to a project where they are injected via Spring string constructors. The reason is that if the SQL statements are in an application context, you don't have to remove all of the " and + to get the SQL to copy/paste on the server. I don't think that's a good reason, but that's what I stepped in to for the moment.
I know this can also be done with properties.
So my question is should the SQL statements go in the application context, Java file, properties file, or some place I'm not thinking of?
Update:
From the replies I got, it seems that prepared statements are the best place for SQL statements. But what about SQL statements that are generated on the fly dynamically? The code will have many different strings that will all be concatenated together to make a query depending on what is passed in. If we have a method with 6 input parameters that could be passed in (or not), I would need an incredible amount of prepared statements to account for all the possibilities.
I've considered using an ORM tool such as Hibernate, but I'm working with an iSeries database and the tables are not well constructed. Perhaps someday I can rewrite Hibernate in and write out the 900 line SQL statements... but one step at a time.
Agree with Thiharas answer, but why not go one step further and save them in .sql files within the application. With each query having its own file it becomes easier to manage.
That is of course if an ORM framework like Hibernate will not be suitable for your application.
There's no rule about where is the best place : it's somehow like "where's the best place to put my keys at home".
If your project needs require you to have the SQL accessible from outside the app, then why not putting them in properties files. In that case, you may want to check that changes in the Sql are still compatible with your app by doing some JUnit tests.
Stored procedures are good because of their execution speed, but bad because they split your app configuration in two places. In addition they are tightly coupled with the database software (which again depending on the project can be a good or bad thing)
Hope my answer helped you asking your self the right questions in your own context.
Best Regards,
Zied
That's not the only reason. When the SQL statements are out side of the Java code you can change it without having to re compile and deploy your application. If the queries are periodically loaded from the files (say once every 8 hours) then you don't even have to do a server restart. That will be very beneficial for the people doing production application support.
Also regarding the first reason you don't consider a good reason; when you have to debug a big assed SQL statement and need to paste it in a query executor removing all + and '"' signs I'm sure you will change your mind :-)

What are the best practices for migrating an Oracle 10g database to Microsoft SQL 2008 R2? Application is using Hibernate

Basically what the title says. Going forward, we need to start supporting both database platforms (and will start writing migrations accordingly), but we need to do the first initial "port".
Our DBAs are confident they can convert the schema, tables, data types, etc. but our developers have less confidence that the DAOs will "just work". Can someone point us towards some resources we can review? Ideally common pitfalls to avoid, specific tests to run, etc. We will of course run the full suite of database tests at the application layer, but want to do as much preparation as possible before then.
Pay attention to and test performance under load. Oracle does some things fundamentally differently than other database vendors. Tom Kyte's excellent book Expert Oracle Database Architecture points out several differences. A couple of highlights:
Oracle never locks data just to read it. Many other databases do.
A writer of data in Oracle never blocks a reader. A reader of data never blocks a writer. Again, many other vendors do.
Not paying attention to things like this can cause big headaches after a conversion when locking issues surface. This is not to imply a superiority of one product over another, rather it just means that what works well with one vendor's product may fail miserably in another, and custom approaches depending on the database may be required.
Ditto (although on a quite simple schema, have to say). "Just worked". Hibernate magic.
I had my peace of mind because we had 100% test coverage for DAO layer. So when schema was recreated on MS SQL, and some table and column names were updated in the mapping (don't remember why, but DBAs asked to, may be naming convention), we just run our tests and found no failed ones.
P.S. Recalled one interesting detail: functional tests were all OK. But when PTE started on MS SQL database, we have found that a concurrent access to one particular table was times slower than on Oracle due to locks propagation. We had to redesign that functionality.
I think the first step would be to get an empty MS SQL schema, use hbm2ddl=true and let Hibernate create the tables there. Then show this to your DBAs and ask if this makes sense.
Populating data is less of a problem, I'd guess queries would be more slippery (especially if you use raw JDBC in some places). You might also want to check query plans for commonly used queries and see if these make sense, too.

SQL server stub for java

I have a java application that is using MSSQL server through the JDBC driver. Is there some kind of stub that I can use for testing? For example I want to test how my application handle cases of connection errors, SQL server out of disk, and other exceptions. It's pretty hard and complex to simulate this with real SQL server.
Thanks
You could write unit tests against your DAOs or repositories returning mock Connection objects using a mock library such as https://mocquer.dev.java.net/.
You'd need a really clean and decoupled application architecture though in order to make this work correctly and provide you with actual test coverage.
You could (assuming the system is architected in a way to make this easy) create your own versions of the DB Access classes (I assume you are using teh statement/preparedstatement interfaces), which would hold the real DB calls and that you can modify to do exactly what you want.
I've done this - it takes a day or so of really boring work.
I don't think there's something like that.
You'd be better off setting up your own database and testing on your machine/lan.
All I know there is out there, is:
freeSQL
db4free
Both support MySQL, but none MS-SQL. I do think that has to do with licensing issues and limitations. So I'm afraid you won't find a similar service for MS-SQL db.
Answering myself with an option I thought of, I'll be glad to hear your inputs on it.
After crawling around, I got to HyperSQLDB, a java-implemented database.
How feasible do you think is to take the source code of HSQLDB, and adding another layer to it, so I can control it and inject pre-defined behaviors to it.
For example, I'll make it run all queries slowly, I'll make it disconnect, etc.
Do you think this idea is worth pursuing? Is it doable in a reasonable amount of time?
If you use something other than MS-SQL, you may cause more testing problems due to incompatibilities and lack of functionality (e.g., transactions) than you solve. So I'm with Carl - use a shim.
If you were looking for unit-test coverage of ordinary behavior, I might think differently.
I haven't used them personally, but the stuff you're talking about sounds like a really good fit for a mocking framework, such as Mockito(docs) or PowerMock. They appear to provide good support for the kind of failure injection you're after. Can someone with experience with either of them (or similar) weigh in? See also How to stub/mock JDBC ResultSet to work both with Java 5 and 6?
execute procedure sp_who2 it will generate the all the current connections and process in your db you can see a column named spid corresponding to each db connection. just type: kill <<spid>> and execute it to terminate any users..etc. but if the spid is less than 50 it means it is a system process and dont kill it. This can help you replicate connection drops.
you can also say ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK_IMMEDIATE this will drop all connections to the said db immediately.
Select ##MAX_Connections as Max_Connections would give you the max connections which can be made to a database (you can set it to a low number to test connection unavailability).
to replicate query timeout.. set the query timeout to a very low number & execute a fairly large query.
to create disk space error, simply redice the size of the db file & do not allow it to grow... then insert data to the database (you'll get an exception).
altert database xxx (file= maxsize= filegrowth=)

Create an in-memory database structure from an Oracle instance

I have an application where many "unit" tests use a real connection to an Oracle database during their execution.
As you can imagine, these tests take too much time to be executed, as they need to initialize some Spring contexts, and communicate to the Oracle instance. In addition to that, we have to manage complex mechanisms, such as transactions, in order to avoid database modifications after the test execution (even if we use usefull classes from Spring like AbstractAnnotationAwareTransactionalTests).
So my idea is to progressively replace this Oracle test instance by an in-memory database. I will use hsqldb or maybe better h2.
My question is to know what is the best approach to do that. My main concern is related to the construction of the in-memory database structure and insertion of reference data.
Of course, I can extract the database structure from Oracle, using some tools like SQL Developer or TOAD, and then modifying these scripts to adapt them to the hsqldb or h2 language. But I don't think that's the better approach.
In fact, I already did that on another project using hsqldb, but I have written manually all the scripts to create tables. Fortunately, I had only few tables to create. My main problem during this step was to "translate" the Oracle scripts used to create tables into the hsqldb language.
For example, a table created in Oracle using the following sql command:
CREATE TABLE FOOBAR (
SOME_ID NUMBER,
SOME_DATE DATE, -- Add primary key constraint
SOME_STATUS NUMBER,
SOME_FLAG NUMBER(1) DEFAULT 0 NOT NULL);
needed to be "translated" for hsqldb to:
CREATE TABLE FOOBAR (
SOME_ID NUMERIC,
SOME_DATE TIMESTAMP PRIMARY KEY,
SOME_STATUS NUMERIC,
SOME_FLAG INTEGER DEFAULT 0 NOT NULL);
In my current project, there are too many tables to do that manually...
So my questions:
What are the advices you can give me to achieve that?
Does h2 or hsqldb provide some tools to generate their scripts from an Oracle connection?
Technical information
Java 1.6, Spring 2.5, Oracle 10.g, Maven 2
Edit
Some information regarding my unit tests:
In the application where I used hsqldb, I had the following tests:
- Some "basic" unit tests, which have nothing to do with DB.
- For DAO testing, I used hsqldb to execute database manipulations, such as CRUD.
- Then, on the service layer, I used Mockito to mock my DAO objects, in order to focus on the service test and not the whole applications (i.e. service + dao + DB).
In my current application, we have the worst scenario: The DAO layer tests need an Oracle connection to be run. The services layer does not use (yet) any mock objects to simulate the DAO. So services tests also need an Oracle connection.
I am aware that mocks and in-memory database are two separates points, and I will address them as soon as possible. However, my first step is to try to remove the Oracle connection by an in-memory database, and then I will use my Mockito knowledges to enhance the tests.
Note that I also want to separate unit tests from integration tests. The latter will need an access to the Oracle database, to execute "real" tests, but my main concern (and this is the purpose of this question) is that almost all of my unit tests are not run in isolation today.
Use an in-memory / Java database for testing. This will ensure the tests are closer to the real world than if you try to 'abstract away' the database in your test. Probably such tests are also easier to write and maintain. On the other hand, what you probably do want to 'abstract away' in your tests is the UI, because UI testing is usually hard to automate.
The Oracle syntax you posted works well with the H2 database (I just tested it), so it seems H2 supports the Oracle syntax better than HSQLDB. Disclaimer: I'm one of the authors of H2. If something doesn't work, please post it on the H2 mailing list.
You should anyway have the DDL statements for the database in your version control system. You can use those scripts for testing as well. Possibly you also need to support multiple schema versions - in that case you could write version update scripts (alter table...). With a Java database you can test those as well.
By the way, you don't necessarily need to use the in-memory mode when using H2 or HSQLDB. Both databases are fast even if you persist the data. And they are easy to install (just a jar file) and need much less memory than Oracle.
Latest HSQLDB 2.0.1 supports ORACLE syntax for DUAL, ROWNUM, NEXTVAL and CURRVAL via a syntax compatibility flag, sql.syntax_ora=true. In the same manner, concatenation of a string with a NULL string and restrictions on NULL in UNIQUE constraints are handled with other flags. Most ORACLE functions such as TO_CHAR, TO_DATE, NVL etc. are already built in.
At the moment, to use simple ORACLE types such as NUMBER, you can use a type definition:
CREATE TYPE NUMBER AS NUMERIC
The next snapshot will allow NUMBER(N) and other aspects of ORACLE type compatibility when the flag is set.
Download from http://hsqldb.org/support/
[Update:] The snapshot issued on Oct 4 translates most Oracle specific types to ANSI SQL types. HSQLDB 2.0 also supports the ANSI SQL INTERVAL type and date / timestamp arithmetic the same way as Oracle.
What are your unit tests for?
If they test the proper working of DDLs and stored procedures then you should write the tests "closer" to Oracle: either without Java code or without Spring and other nice web interfaces at all focusing on the db.
If you want to test the application logic implemented in Java and Spring then you may use mock objects/database connection to make your tests independent of the database.
If you want to test the working as a whole (what is against the modular development and testing principle) then you may virtualize your database and test on that instance without having the risk of doing some nasty irreversible modifications.
As long as your tests clean up after themselves (as you already seem to know how to set up), there's nothing wrong with running tests against a real database instance. In fact it's the approach I usually prefer, because you'll be testing something as close to production as possible.
The incompatibilities seem small, but really end up biting back not so long afterwards. In a good case, you may get away with some nasty sql translation / extensive mockery. In bad cases, parts of the system will be just impossible to test, which I think is an unacceptable risk for business-critical systems.

Categories