Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Using xUnit as a Swiss-Army Testing Toolkit (Does ‘Unit’ Size Matter?) ACCU Conference 2011 Chris Oldwood [email protected] 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 [email protected]