Top Banner
The Art of Unit Testing: How developer should care about code quality Dmytro Patserkovskyi
38

Art of unit testing: How developer should care about code quality

Feb 10, 2017

Download

Engineering

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Art of unit testing: How developer should care about code quality

The Art of Unit Testing:How developer should care about code quality

Dmytro Patserkovskyi

Page 2: Art of unit testing: How developer should care about code quality

2 CULTURE

What is

SOFTWARE TESTING?

Page 3: Art of unit testing: How developer should care about code quality

DIVE INTO THE HISTORY

3

Let’s look over the philosophy of software testing 100 years ago.

Page 4: Art of unit testing: How developer should care about code quality

DIVE INTO THE HISTORY

Debugging

4

Automated Testing

Manual Testing

SUnit(1989)JUnit(2001)

1970’s1950’s

Page 5: Art of unit testing: How developer should care about code quality

DIVE INTO THE HISTORY5

Kent Beck: 1989: "Simple Smalltalk Testing: With Patterns"

Page 6: Art of unit testing: How developer should care about code quality

Software testing it the complex of techniques include the process of executing a program or application with the intent of

finding software bugs.

6

Page 7: Art of unit testing: How developer should care about code quality

PLACE OF UNIT TESTS

7

Let’s find place of unit tests in the ocean of Software Testing.

Page 8: Art of unit testing: How developer should care about code quality

AUTOMATION

MANUAL

PLACE OF UNIT TESTS8

DEBUGGING

SOFTWARETESTING

Page 9: Art of unit testing: How developer should care about code quality

COMPONENT

INTEGRATION

UNIT

PLACE OF UNIT TESTS9

SYSTEM

AUTOMATIONTESTING

Page 10: Art of unit testing: How developer should care about code quality

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.

Page 11: Art of unit testing: How developer should care about code quality

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

Page 12: Art of unit testing: How developer should care about code quality

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

Page 13: Art of unit testing: How developer should care about code quality

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

Page 14: Art of unit testing: How developer should care about code quality

14 CULTURE

WHY ?

Page 15: Art of unit testing: How developer should care about code quality

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

Page 16: Art of unit testing: How developer should care about code quality

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

Page 17: Art of unit testing: How developer should care about code quality

UNIT TESTS

Rich @Before and @After configuration.

@BeforeSuite - @AfterSuite

@BeforeTest - @AfterTest

@BeforeGroups - @AfterGroups

@BeforeClass - @AfterClass

@BeforeMethod - @AfterMethod

17

Page 18: Art of unit testing: How developer should care about code quality

PRINCIPLES OF UNIT TESTS

18

We know how to write units! Don’t we?

Page 19: Art of unit testing: How developer should care about code quality

PRINCIPLES OF UNIT TESTS

19

Principles of Unit Tests:

▹ Easy and fast to run▹ Unit▹ Simple▹ Independent▹ Checking all cases▹ Isolate

Page 20: Art of unit testing: How developer should care about code quality

PRINCIPLES OF UNIT TESTS20

Page 21: Art of unit testing: How developer should care about code quality

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.

Page 22: Art of unit testing: How developer should care about code quality

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.

Page 23: Art of unit testing: How developer should care about code quality

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());

}

@AfterMethodpublic void cleanAfter() {

mailLogsStorage.cleanState();

}

Independent - test should runs with random order and in parallel.

Page 24: Art of unit testing: How developer should care about code quality

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.

Page 25: Art of unit testing: How developer should care about code quality

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.

Page 26: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY

26

Mocking - creating objects that simulate the behaviour of real objects to isolate part of code for unit testing.

Page 27: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY

27

Page 28: Art of unit testing: How developer should care about code quality

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.

Page 29: Art of unit testing: How developer should care about code quality

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

Page 30: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY30

@Test

public void testLogsRefresh() {

LogsStorage storageSpy = spy(logsStorage);

doReturn(true).when(storageSpy).flush();

storageSpy.refresh();

Assert.assertEquals(1, storageSpy.getCountAll());

times(1, storageSpy.flush());

}

Partial Mocks

Page 31: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY31

Looks good… But

Page 32: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY

What if… we have private factory method?

Class MailService {

...

private Session createMailSession() {

...

}

}

32

Page 33: Art of unit testing: How developer should care about code quality

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.

Page 34: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY

What if… we have calls to static method of framework?

Class MailService {

...

public Session sendMail() {

...

// Send message Transport.send(message);

}

}

34

Page 35: Art of unit testing: How developer should care about code quality

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.

Page 36: Art of unit testing: How developer should care about code quality

ISOLATION PHILOSOPHY

PowerMock for legacy code with antipatterns.Mockito is enough for well constructed architecture.

36

Page 37: Art of unit testing: How developer should care about code quality

QUESTIONS

37

Page 38: Art of unit testing: How developer should care about code quality

THANK YOU FOR YOUR TIME

38