SQLUnit – nástroj pre automatizované testovanie storovaných procedúr

203

SQLUnit automatizovane testovanieSQLUnit je testovací framework na regresné a unit automatizované testovanie SQL-storovaných procedúr. Regresné testovanie je testovanie všetkých, už predtým testovaných častí softvérového projektu po každej vykonanej zmene. Väčšina ľudí regresné testovanie vynecháva, pretože si myslí, že vykonaná zmena bola “neškodná”.

SQLUnit testovacie scenáre sa píšu vo formáte XML. SQLUnit samotný je napísaný v Jave, používa JUnit  na prevod testovacích XML šecifikácií na JDBC volania a na porovnania výsledkov generovaných z JDBC volaní s  očakávanými výsledkami.

Java programátori často používajú populárny JUnit na testovanie svojho ​​kódu. Použitie SQLUnit-u na unit testy storovaných procedúry sa tak môže javiť  prirodzeným pokračovaním procesu testovania. Poskytuje pokrytie testami DB-vrstvu, ktorá je často prehliadaná.

Príklad na rýchle pochopenie použitia SQL unitu

Stored procedure, napísana v T-SQL:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

IF (SELECT OBJECT_ID('testSP','P')) IS NOT NULL --means, the procedure already exists
	BEGIN
PRINT 'Procedure already exists. So, dropping and recreating it'
		DROP PROC testSP
	END
GO

CREATE PROCEDURE [testSP]
@msg nvarchar(100),
@msg2 nvarchar(100)
AS

    BEGIN
	select @msg+@msg2 as result
    END
GO

Ako príklad slúži jednouchá SP pre MSSQL Server, ktorá má dva vstupné stringové parametre, ktoré “opíše” zo vstupu ako výsledok.

SQLUnit test, ktorý otestuje stored procedure:

<test name="Testing Stored Proc Hello-World">
       <call connection-id="1">  
              <stmt>testSP ?,?</stmt>
              <param id="1" name="@msg"  type="microsoft_sql_server.NVARCHAR">hello</param>
              <param id="2" name="@msg2" type="microsoft_sql_server.NVARCHAR">-world</param>
       </call>
    <result>
      <resultset id="1">
        <row id="1">
          <col id="1" name="result" type="microsoft_sql_server.NVARCHAR">hello-world2</col>
        </row>
      </resultset>
    </result>
  </test>

XML zápis SQLUnit testu – failne, pretože test posiela parametre “hello” a “–world”, ale očakáva “hello-world2”. Takto bude vyzerať výsledok testu – report:

Vysledky_testovania

Výsledok testu, ak opravíme očakávaný string na “hello-world”:

Vysledky_testovania_Success

Na vytvorenie celej SQLUnit testovacej infraštruktúry budeme okrem vlastného SQLUnitu a jeho dependencies potrebovať 3 vlastné súbory:

  • Build.xml – ANT-ovský build súbor, ktorý obsahuje testovacie targety. Spustí sa “ant o”.
  • Connection.properties – súbor obsahujúci JDBC konfiguráciu na prístup k testovanej DB.
  • Test01.xml – vlastný testovací script.

Build.xml:

  • Target “o” – otvorí report – v tomto prípade Firefox a zobrazí html súbor result_test01.html.
  • Závisí od targetu “report”, ktorý generuje výsledky testu z logu do html pomocu canoo XSLT.
  • Závisí od targetu “def”,ktorý definuje vstupné súbory a formát report.
<?xml version="1.0"?>
<project name="slqlunit" basedir=".">
  <description>SQLUnit tests tasks</description>
  <property name="sql.debug" value="false" />
  <property name="out" value=""/>
  <target name="def">
    <taskdef  name="sqlunit"  classname="net.sourceforge.sqlunit.ant.SqlunitTask">
      <classpath>
		<pathelement location="..\sqlunit-5.0\lib\sqlunit-5.0.jar" />
		<pathelement location="..\junit-4.7\junit-4.7.jar" />
		<pathelement location="..\sqlunit-5.0\lib\log4j-1.2.13.jar" />		
		<pathelement location="..\jdom\jdom-1.1.jar" />		
		<pathelement location="..\xerces-2_9_0\xercesImpl.jar" />
		<pathelement location="..\commons-jexl-2.1.1\commons-jexl-2.1.1.jar"/>
		<pathelement location="..\commons-logging-1.1.3\commons-logging-1.1.3.jar"/>	
		<pathelement location="c:\MyProjects\workspaces\GBS\tools\sqljdbc\sqljdbc4.jar" />
      </classpath>
    </taskdef>
  </target>
  
  <!-- This is repeated for each test or group of tests in case of nested filesets -->
  <target name="run" depends="def">
	<delete file="..\results\result_test01.log"/>
    <sqlunit  testfile="test01.xml"
              haltOnFailure="false"
              debug="${sql.debug}"
              logfile="..\results\result_test01.log"
              logformat="canoo"/>
  </target>
  
  <!-- reporting -->
  <target name="report" depends="run">
     <delete file="..\results\result_test01.html" />
     <xslt in="..\results\result_test01.log"
           out="..\results\result_test01.html"
           style="..\sqlunit-5.0\etc\canoo2html_result_transform.xsl" />
  </target>
  

  <!— opening report -->   
  <target name="o" depends="report"
    description="Opens the html result file in the browser">
    <echo message="Opening result file ..."/>
    <exec executable="C:\Program Files (x86)\Mozilla Firefox\firefox.exe"  spawn="true">
      <arg line="..\results\result_test01.html"/>
    </exec>
  </target>

</project>

Conection.properties:

sqlunit.driver = oracle.jdbc.driver.OracleDriver
sqlunit.url = jdbc:oracle:thin:@localhost:1521:XE
sqlunit.user = roman
sqlunit.password = hesteric

Test01.xml:

Súbor Test01.xml demonštruje okrem vlastého testu storovanej procedúry aj ukážku priameho selectu z tabulky (<testname=”Select with param”>).

<?xml version="1.0"?>
<!DOCTYPE sqlunit SYSTEM "file:docs/sqlunit.dtd">
<sqlunit>
  <connection connection-id="1" extern="connection.properties" transaction-support="off"/>
  
  <test name="Select with param">
    <sql connection-id="1">
      <stmt>select 1 from TABLE where COLUMN=?</stmt>
	  <param id="1" name="@ObjektName"  type="NVARCHAR">Text123</param>
    </sql>
    <result>
      <resultset id="1">
        <row id="1">
          <col id="1" name="col1" type="INTEGER">1</col>
        </row>
      </resultset>
    </result>
  </test>
    
  
  <test name="Testing Stored Proc Hello-World">
	<call connection-id="1">	
		<stmt>testSP ?,?</stmt>
		<param id="1" name="@msg"  type="microsoft_sql_server.NVARCHAR">hello</param>
		<param id="2" name="@msg2" type="microsoft_sql_server.NVARCHAR">-world</param>
	</call>
    <result>
      <resultset id="1">
        <row id="1">
          <col id="1" name="result" type="microsoft_sql_server.NVARCHAR">hello-world2</col>
        </row>
      </resultset>
    </result>
  </test>
 
</sqlunit>

Vlastné spustenie skriptu bude na konzole vyzerať takto:

Spustenie skriptu

A takto by vyzerala storovana procedure pre Oracle aj s jej SQLUnit testom:

CREATE OR REPLACE PROCEDURE get_emp_name(p_empno IN NUMBER,p_empname OUT VARCHAR2)
AS
CURSOR emp_csr
IS
SELECT ename
FROM emp
WHERE empno = p_empno;
BEGIN
OPEN emp_csr;
FETCH emp_csr INTO p_empname;
CLOSE emp_csr;
END get_emp_name;


<sqlunit>
	<connection>
		<driver>oracle.jdbc.driver.OracleDriver</driver>
		<url>jdbc:oracle:thin:@localhost:1521:orcl</url>
		<user>roman</user>
		<password>hesteric</password>
	</connection>
	<test name="Simple PROC call" failure-message="Error with Simple PROC call">
		<call>
			<stmt>{call get_emp_name(?,?)}</stmt>
			<param id="1" name="p_empno" type="INTEGER" inout="in">7934</param>
			<param id="2" name="p_empname" type="VARCHAR" inout="out"></param>
		</call>
		<result>
			<outparam id="2" type="VARCHAR">MILLER</outparam>
		</result>
	</test>
</sqlunit>

A na záver troška teórie

Softvér má nanešťastie jednu zaujímavú vlastnosť. Občas sa totiž správa neočakávateľne. Preto je nevyhnutné vykonať regresné testovanie na overenie, či sa testovaný softvér správa tak ako pred vykonanou zmenou.

Ak sa teda vykoná nejaká zmena, či už za účelom odstránenia chyby, rozšírenia funkčnosti alebo zvýšenia výkonnosti softvéru, je potrebné otestovať, či bola zmena vykonaná tak, ako sa predpokladalo. To znamená, že je potrebné overiť si, či boli odstránené chyby, ktoré sa mali odstrániť, či nové časti systému fungujú správne, alebo či sa zvýšila výkonnosť.

Dobrý článok? Chceš dostávať ďalšie?

Už viac ako 4 200 z vás dostáva správy e-mailom. Nemusíš sa báť, nie každé ráno. Len občasne.

Tvoj email neposkytneme 3tím stranám. Posielame naňho len informácie z robime.it. Kedykoľvek sa môžete odhlásiť.