3b35e94dcd7f0b49a663407895d801b8.ppt
- Количество слайдов: 31
Using x. Unit 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", "+", "-", "*", "/", "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
Consistent Style public void a_c_sharp_test() { var arrangement = new Arrangement(); var result = arrangement. action(); Assert. That(result, Is. Equal. To(expectation)); } create procedure a_sql_test as declare arrangement varchar(100), result varchar(100) exec action @input = arrangement, @output = result exec Assert. Are. Equal @result, "expectation" go
Minimises Dependencies External Service File System Mock External Service Mock File System IExternal. Service IFile. System My. Service Database Mock Database IDatabase
Promotes Arbitrary Code Execution public void Prepare_Should_Elide_Agreement_When_No_Trades_Match() { var trades = new List
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 Database File-System External System 2 The System External System 3 Service 1 Service 2
x. Unit Abuse • Fight the Shadow Cache • Invoke Tear. Down from Set. Up • 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 Add. Customer_Should_Persist_The_Customer () { const id = 1234; const name = "name"; var customer = new Customer(. . . ); using (var connection = Acquire. Connection()) { Customer. Data. Mapper. Add. Customer(customer , connection); Assert. That(Row. Exists("dbo. Customer ", " Customer. Id = {0}" + " AND Customer. Name = '{1}'", id, name), Is. True); } }
Database Set. Up/Tear. Down [Test. Fixture, Test. Category. Database. Test ] public class Some. Entity. Tests : Database. Test. Base { [Test. Fixture. Set. Up] public void Fixture. Set. Up { using(var connection = Acquire. Connection()) { connection. Execute("insert into thingy_table values(1, 2, 3)"); connection. Execute("test. Insert. Thingy(1, 2, 3)"); } } [Test. Fixture. Tear. Down] public void Fixture. Tear. Down { using(var connection = Acquire. Connection()) { connection. Execute("delete from thingy_table"); connection. Execute("test. Delete. All. Thingys "); } } }
Helper Base Class public class Database. Test. Base { public ISql. Connection Acquire. Connection() { return. . . }. . . public bool Row. Exists(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 = Acquire. Connection()) { var reader = connection. Execute. Query(sql ); return (reader. Get. Int("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 Database Trade Data The System 42 Analytics Services
Initial System Test Market Data Service Trade Data Service Calculator [Test, Test. Category. System. Test] 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 Mock External Services Internal Service Performance Test Runner External Service Facade 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 Tests
System Evolution External Market Data Service API Mock Market External Market Data Service API Mock Trade Data. Market Service Data Service [Test, Test. Category. System. Test] 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 Database Public Interface Mock Data Access Data Layer
“The Oldwood Thing” http: //chrisoldwood. blogspot. com Chris Oldwood gort@cix. co. uk


