I've built an important MySQL database, with a lot of view, triggers, functions and procedures.
It's very hard to test, and to not forget anything, so, I've written Cucumber scenarios for all of the features of my DB (Insert, Select, etc., request on functions an procedures etc., and views)
This help us a lot when we test the behavior of all this, and even before writing view and other code, it's very helpful to determinate want we really want to do.
My problem is: after writing Cucumber features, we all test by hand in a MySQL Shell.
I'm new in BDD/TDD and Agile methods, but I've done some search to know how to make some automation, but found nothing very interesting for my case.
Is there somebody who can provide some interesting way to create automation for this?
I don't know Ruby, but by example, is it possible to use RSPec directly with MySQL (with some examples)?
Or in another language, or any solution you can think of!
Thanks in advance!
[EDIT]
If found some interesting things with RSpec and MySQL:
Mysql Support For Cucumber Nagios
mysql_steps.rb
My problem is: I don't have any knoledge with Ruby, RSPec, etc.
I'm working on it with the excellent "Pick Axe" book, and RSPec book from PragProg
But I will be very grateful for a little example of of RSpec steps given the code below:
The MySQL Procedure
DELIMITER $$
CREATE PROCEDURE `prc_liste_motif` (
IN texte TEXT,
IN motif VARCHAR(255),
OUT nb_motif INT(9),
OUT positions TEXT)
BEGIN
DECLARE ER_SYNTAXE CONDITION FOR SQLSTATE '45000';
DECLARE sousChaine TEXT;
DECLARE positionActuelle INT(9) DEFAULT 1;
DECLARE i INT(9) DEFAULT 1;
IF
LENGTH(motif) > LENGTH(texte)
THEN
SIGNAL ER_SYNTAXE
SET MESSAGE_TEXT =
'Bad Request: Le motif est plus long que le texte.',
MYSQL_ERRNO = 400;
END IF;
SET positions = '';
SET nb_motif = 0;
REPEAT
SET sousChaine = SUBSTRING_INDEX(texte, motif, i);
SET positionActuelle = LENGTH(sousChaine) + 1;
IF
positionActuelle < LENGTH(texte) + 1
THEN
IF
LENGTH(positions) > 0
THEN
SET positions = CONCAT(positions, ',');
END IF;
SET positions = CONCAT(positions, positionActuelle);
SET nb_motif = nb_motif + 1;
END IF;
SET i = i + 1;
UNTIL LENGTH(sousChaine) >= LENGTH(texte)
END REPEAT;
END$$
The Cucumber feature:
Feature: Procedure prc_liste_motif
In order to precess a string according to a given unit
I want to know the number of units present in the chain and their positions
Knowing that the index starts at 1
Background: the database mydatabase in our SGBDR server
Given I have a MySQL server on 192.168.0.200
And I use the username root
And I use the password xfe356
And I use the database mydatabase
Scenario Outline: Using the procedure with good values in parameters
Given I have a procedure prc_liste_motif
And I have entered <texte> for the first parameter
And I have entered <motif> for the second parameter
And I have entered <nb_motif> for the third parameter
And I have entered <positions> for the fourth parameter
When I call prc_liste_motif
Then I should have <out_nb_motif> instead of <nb_motif>
Then I should have <out_positions> instead of <positions>
Exemples:
| texte | motif | nb_motif | positions | out_nb_motif | out_positions |
| Le beau chien | e | | | 3 | 2,5,12 |
| Allo | ll | | | 1 | 2 |
| Allo | w | | | 0 | |
An exemple of passed test by hand in MySQL:
$ mysql -h 192.168.0.200 -u root -p xfe356
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.9 MySQL Community Server (GPL)
Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> USE mydatabase
Database changed
mysql> SET @texte = 'Le beau chien';
Query OK, 0 rows affected (0.00 sec)
mysql> SET @motif = 'e';
Query OK, 0 rows affected (0.00 sec)
mysql> SET @nb_motif = NULL;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @positions = NULL;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @out_nb_motif = 3;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @out_positions = '2,5,12';
Query OK, 0 rows affected (0.00 sec)
mysql> CALL prc_liste_motif(@texte, @motif, @nb_motif, @positions);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @nb_motif = @out_nb_motif AND @positions = @out_positions;
+-----------------------------------------------------------+
| @nb_motif = @out_nb_motif AND @positions = @out_positions |
+-----------------------------------------------------------+
| 1 |
+-----------------------------------------------------------+
1 row in set (0.00 sec)
thanks in advance for your help !
Here is some pseudocode for one way you could test your database with RSpec:
describe "prc_liste_motif" do
before(:all) do
# Set up database connection here
end
describe "good values" do
context "Le beau chien" do
let(:texte) { "Le beau chien" }
# Set up other variables here
let(:results) { # call prc_liste_motif here }
it "has the correct out_nb_motif" do
out_nb_motif = # however you derive this from the results of the procedure
out_nb_motif.should == 3
end
it "has the correct out_positions" do
# test out_positions here
end
end
end
end
One thing I noticed in your sample manual test was how you are checking the results:
SELECT @nb_motif = @out_nb_motif AND @positions = @out_positions;
This will tell you whether or not those two values are correct, but if you get 0 results for this query, you do not immediately know which of the two values is incorrect and you do not know what the value you are getting instead is; getting that information requires more investigation.
By splitting up the checking for these two values into 2 RSpec tests, when the tests have finished running you can know if both are correct, if one is incorrect, or if both are incorrect. If one or both are incorrect, RSpec will also return a message for the failed test that says "Expected 3, got 4" which can help you debug faster.
As you add more tests for different inputs, I recommend refactoring the pseudocode I've given here to use shared_examples_for. The PragProg RSpec book that you're already reading is a great reference.
Cucumber's a natural-language BDD tool, which is designed to get non-technical stakeholders on board so that you can have conversations with them about what the system should do. It also lets you reuse steps quite easily - similar contexts, events and outcomes.
If you're writing a database, I think it's likely that your users, and the audience for that database, will be technical. There may also be limited opportunities for reusing steps, so Cucumber may not be the best tool. You're probably right about moving to something like RSpec instead. The English-language tools introduce a layer of abstraction and another aspect to maintenance which can be a pain in the neck, so I'd pick a tool which suits what you're doing, rather than starting with the tool and trying to fit your needs around it.
Once you've done that, you can either use ActiveRecord to create domain-object results from your queries, or you can just call the SQL directly. RSpec is just Ruby with some matchers. This forum might help you.
Something else you could do is to knock up a small application which actually uses your database. Not only will this ensure that your database is genuinely valuable; it will provide users with examples of how to use it. That won't be very difficult to do with Rails. If you go down this route, then you can use Cucumber with something like Webrat or Watir if you want to, because you'll be documenting the kind of things that other applications could use your database for at a higher level. Just make sure that
any live examples you provide go to test data instead of production, and that
if your little example app suddenly turns into the real app (which sometimes happens), you're in a position to spot that happening and take appropriate political and financial steps.
Java also has quite a lot of support for MySQL and you could use Hibernate instead of ActiveRecord, but I think the maintenance costs will be much less in Ruby.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With