Download Using xUnit as a Swiss-Army Testing Toolkit

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Using xUnit as a Swiss-Army Testing Toolkit
(Does ‘Unit’ Size Matter?)
ACCU Conference 2011
Chris Oldwood
gort@cix.co.uk
Stream of Consciousness
•
•
•
•
Developer Driven Testing
The Essence of (x)Unit Testing
Those Pesky Dependencies
Code & Test Evolution in Practice
Stream of Consciousness
•
•
•
•
Developer Driven Testing
The Essence of (x)Unit Testing
Those Pesky Dependencies
Code & Test Evolution in Practice
Text Book Test
string[][]
{
{ "3",
{ "9",
{ "2",
{ "9",
};
tests =
"4",
"1",
"3",
"3",
"+",
"-",
"*",
"/",
"7"
"8"
"6"
"3"
},
},
},
},
void run_tests()
{
var calculator = new Calculator();
foreach(var
{
var lhs
var rhs
var op
test in tests)
= test[0];
= test[1];
= test[2];
var result = calculator(lhs, rhs, op);
assert(result == test[3]);
}
}
Exercise Left for the Reader
External System 1
Database
External System 2
The System
42
External System 3
Services
Lexicon of Testing
Characterisation
End-to-End
Stress
Integration
White Box
Unit
Black Box
Exploration
System
Component
Regression
‘Unit’ Evolution
All Regression
System
Component
Unit
Feedback
Dependencies
Integration
Stream of Consciousness
•
•
•
•
Developer Driven Testing
The Essence of (x)Unit Testing
Those Pesky Dependencies
Code & Test Evolution in Practice
Test == Specification
public void Execute_Should_Elide_Agreement_When_No_Trades_Match()
{
var trades = new List<Trade> { new Trade("trade-id", "product-a") };
var agreement = new Agreement("product-b");
var task = new PreparationTask(trades, agreement);
var result = task.Execute(s_services);
Assert.That(task.Agreement, Is.Null);
}
Consistent Style
public void a_c_sharp_test()
{
var arrangement = new Arrangement();
var result = arrangement.action();
Assert.That(result, Is.EqualTo(expectation));
}
create procedure a_sql_test
as
declare arrangement varchar(100),
result
varchar(100)
exec action @input = arrangement,
@output = result
exec AssertAreEqual @result, "expectation"
go
Minimises Dependencies
External Service
File System
Mock External
Service
Mock File
System
IExternalService
IFileSystem
MyService
Database
Mock Database
IDatabase
Promotes Arbitrary Code Execution
public void Prepare_Should_Elide_Agreement_When_No_Trades_Match()
{
var trades = new List<Trade> { new Trade("trade-id", "product-a") };
var agreement = new Agreement("product-b");
var task = new PreparationTask(trades, agreement);
var result = task.Execute(s_services);
Assert.That(task.Agreement, Is.Null);
}
EXE Stub
Debugger
Test Runner
Custom Test
Harness
Library
LibraryTests
Automated Testing
• Lowers the barrier to running tests
• Regression testing is implicit
• Build server watches your back
Stream of Consciousness
•
•
•
•
Developer Driven Testing
The Essence of (x)Unit Testing
Those Pesky Dependencies
Code & Test Evolution in Practice
Pesky Dependencies
External System 1
External System 2
Database
External System 3
Service 1
The System
File-System
Service 2
xUnit Abuse
• Fight the Shadow Cache
• Invoke TearDown from SetUp
• Test/build failure isn’t absolute
File-System (Reading)
• Source Control directory
• Build server directory
• Resource files
File-System (Writing)
• TEMP directory
• Output directory
Database
•
•
•
•
•
•
Per-user / per-branch workspace
Only need schema not data (Integration)
Can reuse existing unit test database
Use same code revision for compatibility
Use transactions to avoid residual effects
Fake tables with CSV files
Database Asserts
public void AddCustomer_Should_Persist_The_Customer()
{
const id = 1234;
const name = "name";
var customer = new Customer(. . .);
using (var connection = AcquireConnection())
{
CustomerDataMapper.AddCustomer(customer, connection);
Assert.That(RowExists("dbo.Customer",
"
CustomerId = {0}"
+ " AND CustomerName = '{1}'",
id, name),
Is.True);
}
}
Database SetUp/TearDown
[TestFixture, TestCategory.DatabaseTest]
public class SomeEntityTests : DatabaseTestBase
{
[TestFixtureSetUp]
public void FixtureSetUp
{
using(var connection = AcquireConnection())
{
connection.Execute("insert into thingy_table values(1, 2, 3)");
connection.Execute("test.InsertThingy(1, 2, 3)");
}
}
[TestFixtureTearDown]
public void FixtureTearDown
{
using(var connection = AcquireConnection())
{
connection.Execute("delete from thingy_table");
connection.Execute("test.DeleteAllThingys");
}
}
}
Helper Base Class
public class DatabaseTestBase
{
public ISqlConnection AcquireConnection()
{
return . . .
}
. . .
public bool RowExists(string table, string where, string params[])
{
string filter = String.Format(where, params);
string sql = String.Format(
"select count(*) as [Count] from {0} where {1}"
, table, filter);
using (var connection = AcquireConnection())
{
var reader = connection.ExecuteQuery(sql);
return (reader.GetInt("Count") == 1);
}
}
. . .
}
External Systems
• Verify API behaviour
• Test internal façade
• Reliability varies (DEV vs PROD)
Stream of Consciousness
•
•
•
•
Developer Driven Testing
The Essence of (x)Unit Testing
Those Pesky Dependencies
Code & Test Evolution in Practice
System Architecture
Market Data
Database
Trade Data
The System
42
Analytics
Services
Initial System Test
Market
Data Service
Trade
Data Service
Calculator
[Test, TestCategory.SystemTest]
public void Calculate_Answer()
{
. . .
System Tests
var result = c.calculate();
Assert.Equal(result, 42);
}
Test Runner
Analytics Service
Addressing External Risks
External Market
Data Service API
External Trade
Data Service API
External Market
Data Service Tests
External Trade
Data Service Tests
Test Runner
Internal Service Design
External Service
API
External Service
Tests
Performance
Test Runner
External
Service Facade
Mock
External Services
Internal Service
Mock Service
Internal Service
Tests
Data Access Layer
Database
Public Interface
Database Unit
Tests
Database API
Mock Database
API
Data Access
Layer
Mock Data
Access Layer
Data Access
Layer Tests
System Evolution
External Market
Data
Service
API
Mock
Market
External Market
DataMock
Service
API
Trade
DataMarket
Service
Data Service
[Test, TestCategory.SystemTest]
public void Calc_Answer_For_ABC_Plc()
{
. . .
var result = c.calculate();
Assert.Equal(result, 41.75);
Data Trade
Service
Data Service
Calculator
Unit / Integration
/ System Tests
}
Test Runner
External Analytics
Service
Mock
Analytics
Service
Analytics Service
Database
Public
Interface
Mock
Data
Access
Layer
Data Access
Layer
“The Oldwood Thing”
http://chrisoldwood.blogspot.com
Chris Oldwood
gort@cix.co.uk
Related documents