3. DIVE INTO THE HISTORY
3
Let’s look over the philosophy of software
testing 100 years ago.
4. DIVE INTO THE HISTORY
Debugging
4
Automated
Testing
Manual Testing
SUnit(1989)
JUnit(2001)
1970’s1950’s
5. DIVE INTO THE HISTORY5
Kent Beck: 1989: "Simple Smalltalk Testing: With Patterns"
6. ”
Software testing it the complex of
techniques include the process of executing
a program or application with the intent of
finding software bugs.
6
7. PLACE OF UNIT TESTS
7
Let’s find place of unit tests in the ocean of
Software Testing.
10. UNIT TESTS
10
Unit tests – part of code that are designed
to ensure the smallest divisible pieces of
code (units or components) are working
the way they were intended.
11. UNIT TESTS
@BeforeClass
public void testBeforeSuite() {
prepareMailService();
}
@Test(groups = "mail")
public void testEmailService() {
MailService service= generateMailService();
Assert.assertNotNull(service);
}
@Test(dependsOnMethods = { "testMailService" }, groups="mail")
public void testSending() {
MailService service= generateMailService();
Assert.assertTrue(service.sendMail(subject, message));
}
11 Test
Configuration
Preparations
Assertions
Grouping
12. UNIT TESTS
Test - part of code, that check logic of another part of code.
Assertions - mechanism for checking results of lome logic,
defines if our unit test will be success or failed.
Configuration - all attributes and properties of test.
Preparations - part of code, that prepares state and context for our tests.
12
13. UNIT TESTS
Grouping - associates unit tests into groups and suites. Each group or suite should
have common property or characteristic.
13
GROUP SUITE
Contains Methods
Depends on Groups
Annotations Config
Runs Separately
Contains Groups
Flex Configuring
Configuration in XML
Runs Separately
15. UNIT TESTS
Test Dependencies. If a dependent method is fail, all the subsequent test methods
will be skipped, NOT failed.
@Test(groups = "mail")
public void testEmailService() {
MailService service= generateMailService();
Assert.assertNotNull(service);
}
@Test(dependsOnMethods = { "testMailService" }, groups="mail")
public void testSending() {
MailService service= generateMailService();
Assert.assertTrue(service.sendMail(subject, message));
}
15
16. UNIT TESTS
Parameterized Tests. Run your single test for different data sets.
@DataProvider
public Object[][] smtpHosts() {
return new Object[][]{ {"smtp.host1"}, {"mail.host2"} };
}
@Test(dataProvider = "smtpHosts", groups="mail")
public void testSending(String host) {
MailService service= generateMailService(host);
Assert.assertTrue(service.sendMail(subject, message));
}
16
21. ARCHITECTURE OF PROJECT21
Let’s imagine component for sending emails, and try to cover it with unit tests.
Services:
▹ MailService - service for sending emails. Based on Javax Mail.
▹ LogsStorage - service for collecting logs about mails sending and flushing it
to persistent storage.
▹ LogsMailService - service for work with emails and logs.
22. PRINCIPLES OF UNIT TESTS
// Bad
@Test(groups = "mail")
public void testEmailSending() {
MailService service= generateMailService();
Assert.assertNotNull(service);
MailBuilder builder= new MailBuilder();
Mail mail = new MailBuilder().
.newMail()
.addSubject("my mail")
.addRecipient(firstRecipient)
.addRecipient(secondRecipient)
.build();
Assert.assertNotNull(mail);
Assert.assertEquals(EXPECT, mail.getSubject());
...
Assert.assertTrue(service.sendMail(mail));
}
22
// Good
@BeforeTest
public void initialize() {
service= generateMailService();
}
@Test(groups = "mail")
public void testEmailSending() {
Assert.assertTrue(
service.sendMail(prepareMail())
);
}
Unit & Simple - each test covers one piece of code.
23. PRINCIPLES OF UNIT TESTS
// Bad
@Test(groups = "mail")
public void testEmailLogsSuccessful() {
mailLogsStorage.logGood();
Assert.assertEquals(1, mailLogsStorage.getCountGood());
Assert.assertEquals(1, mailLogsStorage.getCountAll());
}
@Test(groups = "mail")
public void testEmailLogsFailed() {
mailLogsStorage.logBad();
Assert.assertEquals(1, mailLogsStorage.getCountBad());
Assert.assertEquals(2, mailLogsStorage.getCountAll());
}
23
// Good
@Test(groups = "mail")
public void testEmailLogsSuccessful() {
mailLogsStorage.logGood();
Assert.assertEquals(1, mailLogsStorage.getCountGood());
Assert.assertEquals(1, mailLogsStorage.getCountAll());
}
@Test(groups = "mail")
public void testEmailLogsFailed() {
mailLogsStorage.logBad();
Assert.assertEquals(1, mailLogsStorage.getCountBad());
Assert.assertEquals(1, mailLogsStorage.getCountAll());
}
@AfterMethod
public void cleanAfter() {
mailLogsStorage.cleanState();
}
Independent - test should runs with random order and in parallel.
24. PRINCIPLES OF UNIT TESTS
// Bad
@BeforeTest
public void initialize() {
service= generateMailService();
}
@Test(groups = "mail")
public void testEmailSending() {
Assert.assertTrue(
service.sendMail(prepareGoodMail())
);
}
24
// Good
@BeforeTest
public void initialize() {
service= generateMailService();
}
@Test(groups = "mail")
public void testEmailSendingSuccess() {
Assert.assertTrue(
service.sendMail(prepareGoodMail())
);
}
@Test(groups = "mail")
public void testEmailSendingFailed() {
Assert.assertFalse(
service.sendMail(prepareBadMail())
);
}
Checking all cases - tests for success case is not enough.
25. PRINCIPLES OF UNIT TESTS
// Bad
@Before
public void before() {
service = new LogMailService();
service.setMailService(new MailService());
}
@Test(groups = "mail")
public void testEmailService() {
Assert.assertTrue(service.sendMail(mail));
}
25
// Good
@Before
public void before() {
service = new LogMailService();
}
@Test(groups = "mail")
public void testEmailService() {
MailService mock = mock(MailService.class)
when(mock.sendMail(mail))
.thenReturn(true);
service.setMailService(mock)
Assert.assertTrue(service.sendMail(mail));
times(1, mock.sendMail(mail));
}
Isolate - encapsulated logic should be covered with separated tests.
26. ISOLATION PHILOSOPHY
26
Mocking - creating objects that simulate
the behaviour of real objects to isolate
part of code for unit testing.
28. ISOLATION PHILOSOPHY28
Mocks - simulated objects that mimic the behavior of real objects in controlled
ways.
Partial mocks - object, created as shell for real one, when you need to stub
several methods of an object leaving the remainder free to respond to calls
normally.
29. ISOLATION PHILOSOPHY29
@Before
public void before() {
service = new LogMailService();
}
@Test
public void testEmailService() {
MailService mock = mock(MailService.class)
when(mock.sendMail(mail))
.thenReturn(true);
service.setMailService(mock)
Assert.assertTrue(service.sendMail(mail));
times(1, mock.sendMail(mail));
}
Mocks
32. ISOLATION PHILOSOPHY
What if… we have private factory method?
Class MailService {
...
private Session createMailSession() {
...
}
}
32
33. ISOLATION PHILOSOPHY
Use dark power of
33
OR.. create a new class and move all private methods to this as
public. Use dependency injection and mocking. This can force you to
use an unwanted design. Private methods are not an option.
34. ISOLATION PHILOSOPHY
What if… we have calls to static method of framework?
Class MailService {
...
public Session sendMail() {
...
// Send message
Transport.send(message);
}
}
34
35. ISOLATION PHILOSOPHY
Use dark power of
35
OR... wrap all static method calls in a separate class and use
dependency injection to mock this object. This will create an extra
layer of unnecessary classes in your application. However, this can
of course be useful if you want to encapsulate the framework to be
able to replace it.