views:

179

answers:

6

I am currently developing a small project of mine that generates SQL calls in a dynamic way to be used by an other software. The SQL calls are not known beforehand and therefore I would like to be able to unit test the object that generates the SQL.

Do you have a clue of how would be the best approach to do this? Bear in mind that there is no possible way to know all the possible SQL calls to be generated.

Currently the only idea I have is to create test cases of the accepted SQL from the db using regex and make sure that the SQL will compile, but this does not ensure that the call returns the expected result.

Edited: Adding more info:

My project is an extension of Boo that will allow the developer to tag his properties with a set of attributes. This attributes are used to identify how the developers wants to store the object in the DB. For example:

# This attribute tells the Boo compiler extension that you want to
# store the object in a MySQL db. The boo compiler extension will make sure that you meet
# the requirements
[Storable(MySQL)] 
class MyObject():
    # Tells  the compiler that name is the PK
    [PrimaryKey(Size = 25)]
    [Property(Name)]
    private name as String

    [TableColumn(Size = 25)]
    [Property(Surname)]
    private surname as String

    [TableColumn()]
    [Property(Age)]
    private age as int

The great idea is that the generated code wont need to use reflection, but that it will added to the class in compile time. Yes the compilation will take longer, but there won't be a need to use Reflection at all. I currently have the code working generating the required methods that returns the SQL at compile time, they are added to the object and can be called but I need to test that the generated SQL is correct :P

A: 

You don't have to test all cases. Make a collection of example calls, be sure to include as many of the difficult aspects that the function will have to handle as possible, then look if the generated code is correct.

Svante
A: 

I would have a suite of tests that put in a known input and check that the generated SQL is as expected.

You're never going to be able to write a test for every scenario but if you write enough to cover at least the most regular patterns you can be fairly confident your generator is working as expected.

If you find it doesn't work in a specific scenario, write another test for that scenario and fix it.

Garry Shutler
+1  A: 

regex

I think that the grammar of SQL is non-regular, but context-free; subexpressions being the key to realize this. You may want to write a context-free parser for SQL to check for syntax errors.

But ask yourself: what is it you want to test for? What are your correctness criteria?

Jonas Kölker
+2  A: 

The whole point of unit testing is that you know the answer to compare the code results to. You have to find a way to know the SQL calls before hand.

To be honest, as other answerers have suggested, your best approach is to come up with some expected results, and essentially hard-code those in your unit tests. Then you can run your code, obtain the result, and compare against the hard-coded expected value.

Maybe you can record the actual SQL generated, rather than executing it and comparing the results, too?

Neil Barnwell
+1  A: 

If you are generating the code, why not also generate the tests?

Short of that, I would test/debug generated code in the same way you would test/debug any other code without unit tests (i.e. by reading it, running it and/or having it reviewed by others).

Anders Sandvig
Unfortunately the code cannot be read because is never written, it is added in the parsing tee used by boo when compiling, and therefore it cannot be read so reading and getting reviewed is not possible :(
mandel
It is not possible to add an intermediate step where the code is written to a file or something?
Anders Sandvig
Yes, but does that mean I have to read the output to make sure it works??? Kinda horrible, isn't it?
mandel
+1, I like the idea it's worth thinking about
Nicolas Dorier
+1  A: 

This seems like a hen-egg situation. You aren't sure what the generator will spit out and you have a moving target to test against (the real database). So you need to tie the loose ends down.

Create a small test database (for example with HSQLDB or Derby). This database should use the same features as the real one, but don't make a copy! You will want to understand what each thing in the test database is for and why it is there, so invest some time to come up with some reasonable test cases. Use your code generator against this (static) test database, save the results as fixed strings in your test cases. Start with a single feature. Don't try to build the perfect test database as step #1. You will get there.

When you change the code generator, run the tests. They should only break in the expected places. If you find a bug, replicate the feature in question in your test database. Create a new test, check the result. Does it look correct? If you can see the error, fix the expected output in the test. After that, fix the generator so it will create the correct result. Close the bug and move on.

This way, you can build more and more safe ground in a swamp. Do something you know, check whether it works (ignore everything else). If you are satisfied, move on. Don't try to tackle all the problems at once. One step at a time. Tests don't forget, so you can forget about everything that is being tested and concentrate on the next feature. The test will make sure that your stable foundation keeps growing until you can erect your skyscraper on it.

Aaron Digulla