Why Unit Testing? Instead of starting by Testing Manually, you start by testing programmatically. You test the code once… … and then continuously afterwards. Guards against others breaking your code. Guards against regression errors. Refactoring Ruthlessly Peace of Mind
Types of Testing – All Important Functional Testing (manual) Integration Testing (automated) (Dosens) Slow Unit Testing (automated) (Hundreds) Localize Failures Fast Dynamic Language Debuggers UI Layer Person View Person Controller Person Model Logic Layer Security Manager Data Layer
Test-First of Test-After? The difference is only When you write your tests? Test-After is painful and boring. Test-First makes unit testing easier. Unit Testing == Good. Win win situation. Test-Driven-Design Test-First drives the Design – Low Coupling. Write only enough to make the test pass. YAGNI
Automatic Test Generation? Only possible after the code has been written. You won’t get tests like… Test_that_user_registration_fails_on_invalid_ID() Doesn’t test Intent, can only test Methods.
Why testing efforts fail When tests become frustrating Integration Tests != Unit Tests Slow Brittle – break unnecessarily Hard to Write due to highly coupled code.
What to test? Single Responsibility Principle Test the responsibility of the Controller Action. ApplicationSuccess view should be returned if application succeeds. ApplicationFailure view should be returned with a reason if application fails.
Our “Unit Test” Database Web Service Session State
Step 1: Extract Class Single Responsibility Principle
Controller – Return correct view and viewModel
UserCreditService – Contains user credit checking functions
Step 2: Use fake Repository and fake UserCreditService Fake objects replace the functionality of the of the real object with an alternate implementaiton, ie returning a canned list of values instead of hitting a database Test Stub is an object that is used by a test to replace a real component to force the system down the path we want for the test. A stub may also record info about how it was called (ie. stub.wasMethodCalled()) Mocks fake implementation by returning hard coded values or values preloaded - they can also verify that the correct calls were made in the right order
Injecting Fakes ControllerTest Tests… Creates… Fake DB Repo Controller Uses… Fake DB Repo
Tip Fine grained is better 100 tests that test 100 things is better … than 10 tests that test a 100 things. Execute the same action many times in different tests and verify different results in each call. Makes errors easier to isolate.
Tips Break Dependencies – strive for low coupling Use Dependency Injection Avoid public Statics Avoid Singletons Use Interfaces to abstract calls to other classes Use Mocks to mimic and test behaviour Single Responsibility Principle – break things into smaller classes and test independently.