BIO PRESENTATION
International Conference On Software Testing Analysis & Review November 15-19, 2004 Anaheim, CA USA
T14
November 18, 2004 1:30 PM
AUTOMATED DATABASE TESTING WITH NUNIT
Alan Corwin Process Builder, Inc.
T14 November 18, 2004 1:30 PM A UTOMATED D ATABASE T ESTING WITH NU - - PDF document
BIO PRESENTATION T14 November 18, 2004 1:30 PM A UTOMATED D ATABASE T ESTING WITH NU NIT Alan Corwin Process Builder, Inc. International Conference On Software Testing Analysis & Review November 15-19, 2004 Anaheim, CA USA Alan Corwin
BIO PRESENTATION
International Conference On Software Testing Analysis & Review November 15-19, 2004 Anaheim, CA USA
November 18, 2004 1:30 PM
Alan Corwin Process Builder, Inc.
Alan Corwin
Alan Corwin has been a software developer, trainer, and course designer for nearly thirty
High Performance Data Integration in the University of Washington’s Advanced Web Development program.
1
2
Isn’t test-driven development planned?
3
Test the Generic Database Requirements Provide a Framework for More Complex Tests Support Rapid Development (Daily Deliverables!) Support Test-Driven Development Allow Tests to be run both by developers and testers. Test engineers and developers should be able to quickly and
easily add test cases as needed.
Eliminate unnecessary communication cycles.
4
Tests are fully automated. Tests are black box (ignorant of the
Tests are infinitely expandable. Tests remain valid even when the
5
VisualStudio.NET (Enterprise Architect
NUnit XML Spy (Optional)
6
tests are rerun.
7
Create the Test Data Dataset Create the Test Data Data File
8
To hold the values necessary to robustly test
To provide a strongly typed DataSet to
To simply the generation and initial
9
First, you don’t “need” a DataSet. They are
DataSets reduce the amount of code required
DataSets increase the readability of code. DataSets eliminate many kinds of errors in
10
Each DataSet is based on an underlying table, view,
Start the DataSet Wizard by adding a new DataSet
Drag the underlying object to the designer. Switch to the XML view. Modify the primary key field. Duplicate the data fields. Add “Update” to the end of each new field name. Save. Demo Here!
11
The format for the test data file was defined. An XSD (XML schema definition file) was just
A Strongly Typed DataSet class was
12
Here’s where XML Spy comes in handy. Open the Schema file you just created in XML Spy Choose the ‘Generate Sample XML File’ command
When the dialog appears, select your options
Save the file in your public TestData directory as an
Edit the data rows as needed. Demo Here!
13
XML Format Means
Editable with a wide variety of tools (including
Built to a known standard supported by every
Easy to transfer to any other data format Easy to read and understand. .NET-ready
For proper testing, you need both a green bar
14
What is NUnit? NUnit Limitations Obtaining and Installing the Product Constructing A Simple Test Running Tests
15
A Public Domain Test Harness for .NET
A Set of Classes to Facilitate Test Development
A Command Line Interface A GUI to Run the Tests from Windows
A Tool For Developer-Centered Testing Developed as JUnit, Ported to .NET, then
16
You can’t test exception propagation easily.
Hard Code Tests Red Bar Tests
Can’t debug when you run from the UI
Unlike user interfaces, database and business objects should throw rather than handle exceptions.
17
http://www.nunit.org Go to the Downloads Page Run the Executable
18
Adding the Harness Reference Creating a Test Class Adding Test Fixture Decorations Write the Test Logic
19
Right-click the References icon for the test
When the Open dialogue appears, navigate
Select all of the DLLs and click Open.
20
Add a new class to the project. Import the NUnit Framework
Imports NUnit.Framework (VB.NET) using NUnit.Framework; (C#)
Add a TestFixture Decoration to the class
<TestFixture()> (VB -- must be on the same line
[TestFixture] (C# -- Must be on the declaration
21
Get the Test Data For Each Test Case
Create the Record Verify the Record Update the Record Verify the Record Delete the Record Verify the Deletion The test logic is often in a different class than the test execution. That is the approach that we use because it makes debugging both the test and the application easier.
22
From the GUI
Green Bar Tests Red Bar Tests
From the Code
23
As a result of adding NUnit and the basic database
To our credit and embarrassment, our prototypes
24
One DataSet Class One Command Helper
Class
Five Stored Procedures One Business Object Class
for Individual Objects
One Business Object Class
for the DataSet
One Test Class for Each
Business Object Class
One Test Data File
containing at least 3 test cases
A Data Entry form for the
individual object class.
A List form for the DataSet
Class
25
NUnit is free, flexible, and easy to use. XML test data files are easy to create and use. NUnit supports a simple, standard approach to
The result of this approach is an automated test
26
Test Logic Set Tests Additional Tests Standardizing Test Classes Resources Automation of Test Automation
27
Three Details Make getting the Data Easy
Our test data is in an XML file. We have a strongly typed DataSet class that matches that
XML file.
Microsoft provides the ReadXML method.
VB Dim myTestData As New MyTestDataSetName() myTestData.ReadXML(fullPathOfTestFile) C# MyTestDataSetName myTestData = New MyTestDataSetName(); myTestData.ReadXML(fullPathOfTestFile);
28
A Strongly Typed DataSet consists of
VB
For Each rowInstance _ As BackSpreadsParameterSetsTestData.SampleBusinessObjectsRow _ in _testSet.Tables[0].Rows _testRow = rowInstance ‘Assign to class variable for common use. Next rowInstance
C#
foreach (BackSpreadsParameterSetsTestData.SampleBusinessObjectsRow rowInstance in _testSet.Tables[0].Rows) {_testRow = rowInstance;} // assign to a class variable for common use.
These Row classes were generated when the Test Data DataSet was created.
29
The Logic of your CRUD tests will depend on the
VB
For Each rowInstance _ As BackSpreadsParameterSetsTestData.SampleBusinessObjectsRow _ in _testSet.Tables[0].Rows _testRow = rowInstance ‘Assign to class variable for common use. RunCrudTestSuite() Next rowInstance
C#
foreach (BackSpreadsParameterSetsTestData.SampleBusinessObjectsRow rowInstance in _testSet.Tables[0].Rows) { _testRow = rowInstance; // assign to a class variable for common use. RunCrudTestSuite(); }
A better design would pass the test row to the CRUD test routine..
30
private void RunCrudTestSuite() { int recordID = theNewID(); TestInitialValues(recordID); UpdateRecord(recordID); TestUpdateValues(recordID); DeleteRecord(recordID); TestDeletion (recordID); }
The recordID ties the tests to the same database
31
protected override int theNewID() { SampleBusinessObject testObject = new SampleBusinessObject(); testObject.Name = _testRow.name; testObject.OptionBotID = _testRow.optionBotID; testObject.Save(); Assert.AreEqual(testObject.Exceptions.Count, 0, "An object loading error occurred."); return testObject.ID; }
Access to the database is allowed only through the business
A new business object is created. The properies are set from the test data row. The business object is saved. A check is made to see that no exceptions occurred. The id of the new record is returned.
Note the Assertion. This is an NUnit Assertion.
32
protected override void TestInitialValues(int idOfObject) { SampleBusinessObject testObject = new SampleBusinessObject(idOfObject); Assert.AreEqual(testObject.Name, _testRow.name, “Wrong name."); Assert.AreEqual(testObject.OptionBotID, _testRow.optionBotID, “Wrong OptionBot ID!"); Assert.AreEqual(testObject.Exceptions.Count, 0, "An object loading error occurred."); }
Tests are very simple.
You put a value into the field. You check to make sure that the same value was
33
protected override void UpdateRecord(int idOfObject) { SampleBusinessObject testObject = new SampleBusinessObject(idOfObject); testObject.Name = _testRow.nameUpdate; testObject.OptionBotID = _testRow.optionBotIDUpdate; testObject.Save(); Assert.AreEqual(testObject.Exceptions.Count, 0, "An object loading error occurred."); return testObject.ID; }
This is very similar to creating the record
Note that we are populating the business
34
protected override void TestUpdateValues(int idOfObject) { SampleBusinessObject testObject = new SampleBusinessObject(idOfObject); Assert.AreEqual(testObject.Exceptions.Count, 0, "An object loading error occurred."); Assert.AreEqual(testObject.Name, _testRow.nameUpdate, “Wrong name."); Assert.AreEqual(testObject.OptionBotID, _testRow.optionBotIDUpdate, “Wrong OptionBot ID!"); }
Update test is almost identical to the initial
Note that we are testing against the update
35
protected override void DeleteRecord(int idOfObject) { SampleBusinessObject testObject = new SampleBusinessObject(idOfObject); testObject.Delete(); }
DeleteRecord is very simple. The logic for
36
protected override void TestDeletion(int idOfObject) { SampleBusinessObject testObject = new SampleBusinessObject(idOfObject); Assert.AreEqual(testObject.Exceptions.Count, 0, "An object loading error occurred."); Assert.AreEqual(testObject.IsNew, true, “The object was not deleted."); }
Update test is almost identical to the initial
Note that we are testing against the update
37
Note that although we had to add a
Add a test in your Test Fixture class to run
38
The test decoration allows the NUnit GUI to
[Test] public void TestBackSpreadParameterSets() { SampleObjectTest _thisTest = new SampleObjectTest(@"H:\TestData\OptionBot\SampleObjects.xml"); _thisTest.RunAllTests(); }
In VB.NET, the correct decoration is ‘<Test()>’.
39
NUnit allows you to specify a set of actions
40
Get the Set Select Subsets Count the Set
41
Are Driven by Customer Requirements Are added at the specification of the test
Are added by the developer. Additional Test Example
42
Test Class Interfaces are used to standardize the language used
for the test methods.
Abstract Test Classes capture the common elements of test
classes. The latest versions of our test classes are currently available at http://www.ProcessBuilder.com for the following languages
43
NUnit Home Page, http://www.nunit.org NUnit Resources
44
Note that this presentation is about how to
Extracting MetaData Code Generation Alternatives