Servoy Tutorial: Automated Testing

Servoy Tutorial Photo Credit: trondjs via Compfight

This Servoy Tutorial is on something most developers tend to ignore, unit testing. We all know that we are supposed to do testing, but do you actually do any automated testing? Are you still relying on the QA department to catch your mistakes? Sure, I know, you are under pressure to implement that next feature, or fix that bug, so you don’t have time.

If you don’t have the time to do it right, when will you have the time to fix it? – John Wooden

The truth is, that we developers are human, and as humans, we are just being lazy. In our laziness, we have no idea how costly this decision is, and the fate it seals for our code. We rely on others to test, and plow ahead, oblivious to the side effects we cause, blind to the defects we leave behind.

You the developer, have the perfect opportunity, as you are writing source code, to quickly put together some unit tests that will validate what you just wrote. By writing unit tests, you will be forced to write code that is more modular in design, resulting in code that is maintainable and extendable. You will discover defects earlier, minimize the bugs you you will have to track down later when the context has been lost, saving you time and money. You will quickly be able to verify new changes have no negative affects, and you will be able to reduce the amount of manual testing required, allowing you to focus more on development, accelerating your productivity. The QA department, on the other hand, will be able to stay focused on business work flow, use case scenarios, and ensuring a quality product is delivered to the market.

Sure, unit testing is not going to prevent all bugs, but what it does do is catch enough of them to make the effort worthwhile. Yes, the product will still need to be tested by QA, but at least a lot of the critical code will have been checked and validated.

What you need to realize, is that any code in your existing project that does not have unit testing, will likely get rewritten. Probably not by you, but by someone else, that is being asked to add new features or fix a bug. It’s a well known fact, that unless the code has unit tests, no matter how brilliant originally, it eventually becomes old legacy code, without any assurance that it still works.

You the developer needs to understand that we spend most of our time maintaining code. On any typical project, most of the time you are modifying and extending what is already there, and rarely will you be writing new code from scratch. Writing code that is modular and highly maintainable, with unit testing, makes it easy for others to work confidently on your code, and pick up where it leaves off. It’s a well documented fact, that eighty percent of the lifetime cost of a piece of software goes into maintenance, and hardly ever is it maintained during its lifetime by the original author.

So, if your the code owner or team lead, then get your team to start using unit testing now. If your a developer on a team, then you start, and lead the way. Be the shining star, earn the respect of your team, minimize your defects, write better code, ensure its used by others, and take pride in your work.

Are you convinced yet? Are you still here? Don’t make me come over there! Yes, let’s face it. Stop being lazy; you have to do unit testing, and the time to start is now!

Okay, so what should we test? What to test is a hotly debated topic among developers. Some developers believe every piece of code needs to be tested. Since we are just getting started, lets ignore trivial code, and write unit tests for any critical or complex parts of our application. Having a a solid test suite on the core code will protect us as we introduce new features, providing the biggest payback on our effort.

Unit testing can be run automatically, and consists of code written to execute specific functionality in your application. Typically, the percentage of your code that is tested by the unit tests is referred to as the test coverage.

In Servoy, we use jUnit for automated unit testing, and writing tests is a very simple and straightforward process. Why don’t we go through a typical scenario, just to demonstrate how easy it is, and that there really is no excuse.

Let’s begin by taking some code and writing some unit tests for it. Some of you might have read my Servoy tutorial on Coding Efficiency. In that Servoy tutorial, we used a simple SQL framework to demonstrate how to write Eclipse templates so that you are more productive.  Let’s use some code from that Servoy tutorial and write some unit tests.

Here is the function we are going to test; it will run some SQL and return a JSDataset. It’s important to note that this code is already modular. It is not buried in one gigantic function that handles calls for datasets, foundset or raw SQL  queries. As shown in the prior Servoy tutorial, each of these functions has been written as a separate method, sharing a single error handler. This makes it easy to test, maintain, and scale. This is what we are talking about when we say testing will force you to write better code. Perhaps in a future Servoy tutorial we can focus on how to write more modular code.

Here is the error handler that is used with the sqlDataset function.

Okay, so let’s write our first unit test. You can write this unit test anywhere in your solution, but I would recommend that you keep them in their own separate .js file for each module. That way you can use two windows in Servoy to show the test code in one window, and the code you are testing in the other window. Quite often you will find yourself tweaking the original code to handle new situations you think of as you are writing tests. The most important thing, however, is that all your test function names start with the prefix “test_”. This is what Servoy looks for when you run unit testing on your solution.

In the first test, I want to simply verify that using the sqlDataset function gives me the expected data. Here is what I came up with:

Okay, so in this test, I am going to look for a specific record that I know should be in my table. If I get the right record back, I know it is working. I check this using junit.assertEquals. It verifies that the two values are equal and fails if they are not equal.  You don’t have to include a message like I did; its optional. To run this test, I right-mouse click on my solution and select “Run JS Unit Test(s)”.

junit_1

In my JUnit view, I can see the test ran, and that there are no errors or failures. Seriously, that’s it. Could it be any simpler? In older versions of Servoy, you had to write your tests in a separate solution, and make it the active solution before you ran the tests. But now, you can simply run your tests directly in the active solution, so its fast and convenient.

junit_2

Okay, so we did one test to make sure that we get back the expected data. So, we can at any time verify that our SQL database method is still functioning. If someone were to inadvertently affect the method and break this basic functionality, this test would fail, showing us the details in the “Failure Trace” window. We would then be able to double-click on the failure and go right to the test that failed.

You can write all kinds of tests using different asserts. Here are a bunch of examples.

I can call functions to return test criteria, as I do in the second last assertTrue that calls checkPK(). The checkPK() function would be located somewhere towards the end of the test procedure and would look like this:

Alright, so let’s do another test. Let’s send the method a malformed SQL query (notice COUNT is missing (*)) and make certain that the error handler reports the problem, and that the function returns null (you could of course have it return a specific error message, but in my case I output that message to the console). We do this in the same test procedure we wrote, we just do a simple setup for the test case and then do the assert.

Here is my second test:

Here is what I see in the Console:

Note that in this particular situation, we did not have to do any elaborate setup or tear-down. However, in some cases, you will have to prepare data for the test, like maybe create an order for an actual customer. This is called the setup function, and in this case it would create an order and then test that the order total is still the correct value. You would then delete the order from the system after the test, in a tear-down function. Using a parameter driven setup function, you can automatically test dozens of unique order variations, without any user intervention. Imagine validating a hundred different order scenarios automatically, each time you make a new production build. Try and tell me your QA department can do that! By the way, I do want to mention that these types of elaborate setup and tear-down tests should go into their own separate module. That way you can add the module and include them in your unit testing only when you are getting ready to do a production release. I don’t think you would want these tests running all the time during the development cycle.

Hey, I just thought of something. This function expects a SQL query and an array of parameters. What if the wrong number of parameters are passed for a given SQL query? Maybe we should handle that possibility? Right, back to work; here is what I came up with:

You can see I added a check to see if oSQL.sql is using parameters (“?”), and if so, another check to then confirm that the number of arguments in oSQL.args matches the number of parameters specified in oSQL.sql. If they don’t, it will handle the situation by returning null (could be another specific error message if you want).  I can now write an assert to verify that this function will catch a miss-match in expected parameters using a test like this:

Okay, that’s better, but, if you refer back to the previous Servoy tutorial, this little SQL handler framework actually has three functions, sqlDataset, sqlFoundSet, and sqlRaw, and we should do this missing parameter check in all three. We need to decouple this parameter check and make it a function that is shared by our three SQL functions, just like our error handler. That way, if we think of any other error checking we want to do, we can make the modification in one place. In addition to that, instead of writing unit tests to validate our param check in each of the three SQL functions, we can just check the new function we will create with one set of unit tests.

Hmmm…, the other thing I just noticed, is that our error handler could return null, in which case we can simplify the error handler call in our SQL functions as well.

Right, back to work. Here is the new sqlDataset function I came up with:

Here is my new sqlCheckQuery function:

And, here are the unit tests to validate the new function.

Sweet! Now that code looks a lot better to me. I’m going to be able to sleep tonight.

Hey! Did you notice what just happened? As we wrote some unit tests for our brilliant sqlDataset function, we realized that we should handle another potential error, where the wrong number of parameters are provided for the SQL statement. We ended up modifying our code, decoupling it into modularized functions, and our mini SQL framework is now even better. We handle potential errors elegantly (no big error dialog presented to the user), and all our code is validated by unit tests. This re-writing process was prompted by the fact that we needed to write some unit tests for our code, and this forced us to look at it from a different perspective. It helped us write better code! Other developers will use this function and extend it to suit their needs. This code is on its way to becoming a permanent part of our application; it is not going to end up as old untested legacy code.

Of course, we could think up more things that could go wrong, write code to handle those situations, and then write more tests to verify everything is working, but honestly, those will build up over time, once you get started with unit testing. As a general rule, you should try to unit test each branch in your function.

So there you have it; a gentle introduction to unit testing. It’s not scary, and its not a lot of work. Its critical that you do it; for your team, for your product, for your customers, for your career.  Don’t listen to anyone that tells you not to bother, and stop being lazy! It will force you to write better code, and your code will live on.

That concludes this Servoy tutorial. If you liked this Servoy tutorial, please check out some of the other Servoy tutorials in the “Related Posts” below. Also, please subscribe, and receive a notification when new ones are posted.

Gary Dotzlaw
Gary Dotzlaw has 20+ years of experience as a professional software developer and has worked with over 100 companies throughout the USA and Canada. Gary has extensive qualifications in all facets of the project life cycle, including initial feasibility analysis, conceptual design, technical design, development, implementation and deployment. Gary is an expert Servoy Developer, with extensive large-commercial project experience, and has written numerous advanced tutorials on Servoy development.