10. Assertions - exceptions
● Microsoft
try
{
DivideBy(0);
Assert.Fail();
}
catch(ArgumentException ex)
{
Assert.AreEqual("Cannot divide by 0", ex.Message);
}
11. Fixtures
● Microsoft
● Jasmine
● JUnit
[TestInitialize] public void Initialize() { ... }
[TestCleanup] public void Cleanup() { ... }
beforeEach(function () { ... });
afterEach(function () { ... });
@Before public void before() { ... }
@After public void after() { ... }
12. Runners
● Microsoft
● Jasmine
● JUnit
Visual Studio
Test | Run | All Tests
Grunt & Karma
npm test
IntelliJ IDEA
Run | Configurations | JUnit
13. Debugging
● Microsoft
● Jasmine
● JUnit
Visual Studio
Test | Debug | All Tests
Grunt & Karma & Chrome
npm run test:chrome
IntelliJ IDEA
Debug | Configurations | JUnit
14. Exercise - unit testing
● Try out assertions
● Equality and sameness
● Floating point
● Collections
● Exceptions
● Verify that fixture methods run for every test
● Debug a test
15. Workflow of TDD / BDD
Failing
test
Succeeding
test
Good
design Refactor
Code
Test
Behavior
Think, talk
16. TDD Demo - IP# -> Location display
● Convert this JSON ● To a display string
San Francisco, California
Farum, Denmark
Philippines
{
CountryCode = "US",
Country = "USA",
Region = "California",
City = "San Francisco"
}
{
CountryCode = "DK",
Country = "Denmark",
Region = "Hovedstaden",
City = "Farum"
}
{
CountryCode = "PH",
Country = "Philippines",
Region = "",
City = ""
}
18. Exercise - TDD
● Input: a date
● Output: the time since that date, human readable
● "2 minutes ago"
● "1week ago"
● "3 months ago"
● Think first about the precise behavior
● Then write one test for the simplest case not covered yet
● and make it fail for the right reason
● Then write the code to make the test pass
● ...repeat :)
19. ● Enjoy more efficient and predictable course of development
● Find and fix bugs faster
● Prevent bugs from reappearing
● Improve the design of our software
● Reliable documentation
● Way more fun :)
Why is TDD a good thing?
21. TDD - questions
● How fine grained is the TDD cycle?
● Do we always write tests before code?
● Why can't we just write the tests afterwards?
● How many tests are enough?
● How do we test private methods?
● Do we have to setup all dependencies?
● What about our legacy code?
22. What is good design?
● One element of good design is loose coupling
● Use interfaces (for static languages)
● Inject dependencies
● Avoid using new:
● Inject dependencies instead:
private IEmailSvc emailSvc;
public Notifier(IEmailSvc emailSvc)
{
this.emailSvc = emailSvc;
}
public void Trigger()
{
emailSvc.SendEmail();
public void Trigger()
{
var emailSvc = new EmailSvc();
emailSvc.SendEmail();
}
23. Stubs and mocks
● When testing an object X, that depends on an object Y
● replace the real Y with a fake Y
● Benefits
● Only test one thing (X) at a time
● Faster tests (Y may be slow)
● Simpler (Y may depend on Z etc)
● Examples:
● Time
● Database
● Email
● HttpContext
Notifier
EmailSvc
IEmailSvc
EmailSvcStub
NotifierTest
24. Stubs
● Hand crafted
● More effort to write
● Easier to maintain
● Can be more "black box" than mocks
25. Mocks
● Mocks are automatically generated stubs
● Easy to use
● More "magical", may be slower
● More effort to maintain
● Will be more "white-box" than stubs
● Example frameworks:
● C#: NSubstitute
● JavaScript: Sinon.JS
● Java: Easymock / Powermock
26. Stubs - example
public class EmailSvcStub : IEmailSvc
{
public int NumberOfEmailsSent { get; set; }
public void SendEmail()
{
++NumberOfEmailsSent;
}
}
[Test]
public void Trigger()
{
// setup
var emailSvc = new EmailSvcStub();
var notifier = new Notifier(emailSvc);
// invoke
notifier.Trigger();
// verify
Assert.That(emailSvc.NumberOfEmailsSent, Is.EqualTo(1));
}
27. Mocks - example
[Test]
public void Trigger()
{
// setup
var emailSvc = Substitute.For<IEmailSvc>();
var notifier = new Notifier(emailSvc);
// invoke
notifier.Trigger();
// verify
emailSvc.Received(1).SendEmail();
}
28. Test data builder - example
[Test]
public void GetResponseMedia()
{
// given
var stub = new StubBuilder
{
Questions = new [] {
new QuestionBuilder { Name = "MEDIA" },
},
Participants = new[] {
new ParticipantBuilder { Name = "Lars", Votes = new [] {
new VoteBuilder { Question = "MEDIA", Responses =
new ResponseBuilder(new byte [] {1, 2, 3}) },
}},
},
}.Build();
var voteController = new VoteController(stub.Session);
// when
var result = voteController.GetResponseMedia(vote.Id, true) as MediaResult;
// then
Assert.That(result.Download, Is.True);
Assert.That(result.MediaLength, Is.EqualTo(3));
Assert.That(TfResponse.ReadAllBytes(result.MediaStream), Is.EqualTo(new byte[] {1, 2, 3}));
}
29. Legacy code
● Add pinning tests
● special kinds of unit tests for legacy
code
● verifies existing behaviour
● acts as a safety net
● Can be driven by change requests
● Refactor the code to be able to write
unit tests
● Add unit test for the change request
● Track coverage trend for existing
code
● and make sure it grows