lecture 14 design for testing
play

LECTURE 14: DESIGN FOR TESTING CSE 442 Software Engineering - PowerPoint PPT Presentation

LECTURE 14: DESIGN FOR TESTING CSE 442 Software Engineering Easiest Code to Test Easiest Code to Test Easiest Code to Test Functional Languages Coding in Most Languages Side-effects common & makes testing more difficult


  1. LECTURE 14: DESIGN FOR TESTING CSE 442 – Software Engineering

  2. Easiest Code to Test

  3. Easiest Code to Test

  4. Easiest Code to Test Functional Languages

  5. Coding in Most Languages ¨ Side-effects common & makes testing more difficult

  6. Suggestions for Tests public class Time { private int second, minute, hour; // Assume toString() also exists public void advanceTime(int secs) { second = second + secs; minute = minute + (second / 60); second = second % 60; hour = hour + (minute / 60); minute = minute % 60; while (hour > 12) { hour = hour – 12; } } }

  7. Suggestions for Tests public class Time { private int second, minute, hour; // Assume toString() & getters for fields also exist public void advanceTime(int secs) { second = second + secs; minute = minute + (second / 60); second = second % 60; hour = hour + (minute / 60); minute = minute % 60; while (hour > 12) { hour = hour – 12; } } }

  8. Tests Access Inputs & Outputs public class Time { private int second, minute, hour; // Assume toString() & getters for fields also exist public void advanceTime(int secs) { second = second + secs; minute = minute + (second / 60); second = second % 60; hour = hour + (minute / 60); minute = minute % 60; while (hour > 12) { hour = hour – 12; } } }

  9. Important Test Concept ¨ Errors likely in calculations, especially if complex ¤ Entire goal is finding & HELPING FIX bugs using tests ¤ Needs simple code that can be understood & examined ¤ Also requires easy way to set inputs & see outputs ¨ Do best to separate calculations & state changes ¤ Calculations long & complex needing lots of testing ¤ Need to be focus of testing & results important to test ¤ State changes simple & unlikely to be bug source

  10. Important Test Concept #2 ¨ Large calculations complex & tests tough to plan How could anyone climb that?

  11. Important Test Concept #2 ¨ Decompose calculations into smallest pieces ¤ Smaller functions easier to read, test, & debug ¤ Test each function separately to make certain they work ¤ Once pieces done, write function combining results

  12. Decompose This Code public class Time { private int second, minute, hour; public void advanceTime(int secs) { second = second + secs; minute = minute + (second / 60); second = second % 60; hour = hour + (minute / 60); minute = minute % 60; while (hour > 12) { hour = hour – 12; } } }

  13. Decomposed For Testing! public class Time { private int second, minute, hour; public int advanceSeconds(int secs) { second = second + secs; advanceMinutes(second / 60); second = second % 60; return second; } public int advanceMinutes(int mins) { minute = minute + mins; advanceHours(minute / 60); minute = minute % 60; return minute; } public int advanceHours(int hrs) { hour = hour + hrs ; while (hour > 12) { hour = hour – 12; } return hour; } }

  14. Define Modules Carefully

  15. Define Modules Carefully Write code so important calculations testable

  16. Not Just For Assignments ¨ Also important to separate I/O from calculations ¤ I/O tough to test , since requires reviewing output ¤ But, since built into language, even harder to fix ¨ Write functions returning Strings or bytes with data ¤ Second set of functions take in data and just output it ¤ But this can create performance issues & other problems ¤ Solution relies on understanding another issue

  17. Dependency Management ¨ Want to keep coupling between classes loose ¨ Dependency needed to preserve single responsibility public class Engine { /* Code here */ } public class Car { private Engine motor; public Car() { motor = new Engine(); } /* Even more code here */ }

  18. Why Could drive() Fail? public class Engine { /* Code here */ } public class Car { private Engine motor; public Car() { motor = new Engine(); } public int drive(int distance) { int gasUsed = motor.move(distance); return gasUsed; } /* Even more code here */ }

  19. Dependency Inversion

  20. Dependency Inversion ¨ Make classes advertise their dependencies ¤ Do this by adding parameters within constructor ¤ Improves testability by allowing other options ¤ Makes implementations easier when Null is an object public class Engine { /* Code here */ } public class Car { private Engine motor; public Car() { motor = new Engine(); } /* Even more code here */ }

  21. Dependency Inversion ¨ Make classes advertise their dependencies ¤ Do this by adding parameters within constructor ¤ Improves testability by allowing other options ¤ Makes implementations easier when Null is an object public class Engine { /* Code here */ } public class Car { private Engine motor; public Car(Engine inMotor) { motor = inMotor; } /* Even more code here */ }

  22. Tests Dependency Inversion ¨ Dependency inversion enables using stubs & mocks ¨ Stub object fakes data to allow code to be tested ¤ Important when actual data uncontrollable or not coded: Internet traffic Database queries File I/O Multithreaded interactions

  23. Where Stub Needed public class NuclearPowerPlant { private NuclearReactor reactor; public NuclearPowerPlant() { reactor = new NuclearReactor("SNPP"); } public boolean checkForBreach() { if (!reactor.withinLimits()) return reactor.alarmSounding(); return false; } }

  24. Passed Test?

  25. Adding Dependency Inversion public class NuclearPowerPlant { private NuclearReactor reactor; public NuclearPowerPlant(NuclearReactor n){ reactor = n; } public boolean checkForBreach() { if (!reactor.withinLimits()) return reactor.alarmSounding(); return false; } }

  26. Create Interface For Stub public interface NR { public boolean withinLimits(); public boolean alarmSounding(); } public class NuclearPowerPlant { private NR reactor; public NuclearPowerPlant(NR n){ reactor = n; } public boolean checkForBreach() { if (!reactor.withinLimits()) return reactor.alarmSounding(); return false; } }

  27. Why We Write Stubs Testing NuclearPowerPlant NOT NuclearReactor

  28. Create Stub Class ¨ Only write code test needs – only reason stub exists ¤ Code for NuclearReactor developed separately ¨ ONLY purpose is testing other classes code ¤ Often hard-code values; make it as simple as possible ¤ Stub used to simplify; avoid using files, networks, etc. ¨ Use of duct tape & stubs similar ¤ Not for serious fix, but useful in a pinch

  29. Writing Stub Class public interface NR { public boolean withinLimits(); public boolean alarmSounding(); } public class MeltdownStub implements NR{ public boolean withinLimits() { return false; } public boolean alarmSounding() { return true; } }

  30. Using Stubs ¨ Can now run class in many different ways ¤ Constructor passed stub instance to test code works ¤ Actual reactor instance in production to avoid warnings ¨ If more tests desired, can create additional stubs ¤ Easy to write stub, since all of the data is hard-coded ¤ Tests must be convincing & errors not due to test code

  31. Using Stubs ¨ Can now run class in many different ways ¤ Constructor passed stub instance to test code works ¤ Actual reactor instance in production to avoid warnings ¨ If more tests desired, can create additional stubs ¤ Easy to write stub, since all of the data is hard-coded ¤ Tests must be convincing & errors not due to test code or

  32. Using Stub Class public class MeltdownStub implements NR { public boolean withinLimits() { return false; } public boolean alarmSounding() { return true; } } public class NuclearPowerPlant { public boolean checkForBreach() { if (!reactor.withinLimits()) return reactor.alarmSounding(); return false; }} @Test public void testTMI() { NR ms = new MeltdownStub(); NuclearPowerPlant tmi=new NuclearPowerPlant(ms); assertTrue(tmi.checkForBreach()); }

  33. Stub Class Review ¨ Define interface so hard-to-use classes have options ¤ Interface defines minimum number of methods ¤ Update existing class to implement this interface ¨ Requires using dependency inversion in holding class ¤ Pass instance to constructor & eliminate new command ¤ Not a bad idea, in general, since also improves coupling ¨ Stub(s) used in test(s); actual class in production ¤ Easy to create many stubs, since often provide constant ¤ Testing for hard situations or while waiting on others

  34. Tests Dependency Inversion ¨ Dependency inversion enables using stubs & mocks ¨ Mock object tracks calls to test class interactions ¤ Important when important to check call or arguments ¤ Checks class interactions and not method results ¤ Test case uses results in mock object to see if passing

  35. Where Mock Needed public class EmergencySystem { private AlertReport reporter; public EmergencySystem(AlertReport r) { reporter = r; } public void incomingMissle() { reporter.sendEASAlert(); } }

  36. Passed Test?

  37. Using Mock Class public class MockAlert implements AlertReport { public boolean alertSent = false; public boolean sendEASAlert () {alertSent = true;}} public class EmergencySystem { public void incomingMissle() { reporter.sendEASAlert(); } } @Test public void testNOTHawaii() { AlertReport ma = new MockAlert(); EmergencySystem eas=new EmergencySystem(ma); eas.incomingMissle(); assertTrue(ma.alertSent); }

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend