using xunit as a swiss-army testing toolkit (does unit size matter?) accu conference 2011 chris...

31
Using xUnit as a Swiss-Army Testing Toolkit (Does ‘Unit’ Size Matter?) ACCU Conference 2011 Chris Oldwood [email protected]

Upload: mary-ayers

Post on 26-Mar-2015

215 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Using xUnit as a Swiss-Army Testing Toolkit

(Does ‘Unit’ Size Matter?)

ACCU Conference 2011

Chris [email protected]

Page 2: 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

Page 3: 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

Page 4: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Text Book Teststring[][] tests = { { "3", "4", "+", "7" }, { "9", "1", "-", "8" }, { "2", "3", "*", "6" }, { "9", "3", "/", "3" },};

void run_tests(){ var calculator = new Calculator();

foreach(var test in tests) { var lhs = test[0]; var rhs = test[1]; var op = test[2];

var result = calculator(lhs, rhs, op);

assert(result == test[3]); }}

Page 5: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Exercise Left for the Reader

External System 1 External System 2 External System 3

The System

42

ServicesDatabase

Page 6: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Unit

Integration

System Component

Stress

Lexicon of Testing

End-to-End

Regression

White Box

Black Box

Characterisation

Exploration

Page 7: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

System

Integration

Component

Unit

Dependencies

Feedback

‘Unit’ Evolution

All Regression

Page 8: 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

Page 9: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

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);}

Page 10: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Consistent Stylepublic void a_c_sharp_test(){ var arrangement = new Arrangement();

var result = arrangement.action();

Assert.That(result, Is.EqualTo(expectation));}

create procedure a_sql_testas declare arrangement varchar(100), result varchar(100)

exec action @input = arrangement, @output = result

exec AssertAreEqual @result, "expectation"go

Page 11: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Minimises Dependencies

MyService

External Service DatabaseFile System

Mock ExternalService

IExternalService IFileSystem IDatabase

Mock FileSystem

Mock Database

Page 12: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

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);}

LibraryEXE Stub

Test Runner LibraryTestsDebugger

Custom TestHarness

Page 13: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Automated Testing

• Lowers the barrier to running tests

• Regression testing is implicit

• Build server watches your back

Page 14: 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

Page 15: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Pesky Dependencies

External System 1 External System 2 External System 3

The SystemService 2

Service 1

File-System

Database

Page 16: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

xUnit Abuse

• Fight the Shadow Cache

• Invoke TearDown from SetUp

• Test/build failure isn’t absolute

Page 17: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

File-System (Reading)

• Source Control directory

• Build server directory

• Resource files

Page 18: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

File-System (Writing)

• TEMP directory

• Output directory

Page 19: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

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

Page 20: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

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); }}

Page 21: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

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"); } }

}

Page 22: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Helper Base Classpublic 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); } }

. . .}

Page 23: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

External Systems

• Verify API behaviour

• Test internal façade

• Reliability varies (DEV vs PROD)

Page 24: 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

Page 25: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

System Architecture

Market Data Trade Data Analytics

The System

42

ServicesDatabase

Page 26: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Initial System Test

MarketData Service

TradeData Service

Analytics Service

Calculator

Test Runner

System Tests

[Test, TestCategory.SystemTest]public void Calculate_Answer(){ . . .

var result = c.calculate();

Assert.Equal(result, 42);}

Page 27: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Addressing External Risks

External MarketData Service API

External TradeData Service API

External MarketData Service Tests

External TradeData Service Tests

Test Runner

Page 28: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Internal Service Design

External ServiceAPI

External ServiceTests

Internal Service

ExternalService Facade

Internal ServiceTests

MockExternal Services

PerformanceTest Runner

Mock Service

Page 29: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

Data Access Layer

DatabasePublic Interface

Database UnitTests

Data AccessLayer

Data AccessLayer Tests

Database APIMock Database

API

Mock DataAccess Layer

Page 30: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

DatabasePublic Interface

External AnalyticsService

External MarketData Service API

External MarketData Service API

System Evolution

Mock MarketData Service

Mock TradeData Service

Mock AnalyticsService

Calculator

Test Runner

Unit / Integration/ System Tests

[Test, TestCategory.SystemTest]public void Calc_Answer_For_ABC_Plc(){ . . .

var result = c.calculate();

Assert.Equal(result, 41.75);}

Mock DataAccess Layer

MarketData Service

TradeData Service

Analytics Service

Data AccessLayer

Page 31: Using xUnit as a Swiss-Army Testing Toolkit (Does Unit Size Matter?) ACCU Conference 2011 Chris Oldwood gort@cix.co.uk

“The Oldwood Thing”http://chrisoldwood.blogspot.com

Chris Oldwood

[email protected]