Next Generation Testing Cdric Beust, Google Alexandru Popescu, - - PowerPoint PPT Presentation

next generation testing
SMART_READER_LITE
LIVE PREVIEW

Next Generation Testing Cdric Beust, Google Alexandru Popescu, - - PowerPoint PPT Presentation

Next Generation Testing Cdric Beust, Google Alexandru Popescu, InfoQ Alexandru Popescu, InfoQ QCon San Francisco November 2007 QCon, San Francisco Menu 1) TestNG features that we like 2) Designing for testability QCon, San Francisco


slide-1
SLIDE 1

Next Generation Testing

Cédric Beust, Google Alexandru Popescu, InfoQ

QCon, San Francisco

Alexandru Popescu, InfoQ

QCon San Francisco November 2007

slide-2
SLIDE 2

Menu

1) TestNG features that we like

QCon, San Francisco

2) Designing for testability

slide-3
SLIDE 3

TestNG Overview

  • Annotations based
  • Groups
  • Dependent test methods

QCon, San Francisco

  • Dependent test methods
  • Parallel/Multithreaded testing

– Thread pools, timeouts

  • Customizable runtime configuration
  • Flexible plug-in API
slide-4
SLIDE 4

TestNG features we like

  • Groups
  • Data Providers

QCon, San Francisco

  • Data Providers
  • Dependent tests
slide-5
SLIDE 5

→ Groups

  • Data providers

QCon, San Francisco

  • Data providers
  • Dependent tests
slide-6
SLIDE 6

TestNG Groups

  • Problem: configure what tests should be

run

  • Most of the time, you do this:

QCon, San Francisco

  • Most of the time, you do this:

– either by artificial grouping (directory based, name based, etc.) – creating configuration like classes that describe the inclusion rules (same as suite() in xUnit)

slide-7
SLIDE 7

Groups with TestNG

  • Test method:

@Test(groups={"one", "two"})

  • Configuration method:

QCon, San Francisco

  • Configuration method:

@Before and @After methods can also belong to groups

  • Define special group lifecycle methods:

@BeforeGroup/@AfterGroup

slide-8
SLIDE 8

Running groups

  • Supported by all TestNG launchers

– Command line – Ant

QCon, San Francisco

– Eclipse (launch configurations can be shared between the team members) – IntelliJ IDEA plug-ins

  • Exclude running specific groups
slide-9
SLIDE 9

Example

public class GroupTest { @Test(groups={"one", "two"} public void commonTest() {} @Test(groups={"one"}) public void groupOneOnly() {}

QCon, San Francisco

public void groupOneOnly() {} @Test(groups={"two"}) public void groupTwoOnly() {} @BeforeGroups(groups={“one”}) public void beforeGroupOne() { // run only before group “one” }

}

slide-10
SLIDE 10

Group categories

Examples of group names:

  • test type: unit, functional, integration, system, acceptance.
  • test size: small, medium, large
  • functional description: web, gui, html, jsp, servlet, database,

QCon, San Francisco

  • functional description: web, gui, html, jsp, servlet, database,

back-end.

  • speed of the test: slow, fast.
  • procedural: check-in, smoke-test, milestone, release.
  • platform: os.win32, os.linux, os.mac-os
  • hardware: single-core, multi-core, dual-cpu, memory.1gig,

memory.10gig

  • runtime schedule: week-days, weekends, nightly, monthly
slide-11
SLIDE 11

Hints on using groups

  • Groups are not mutually exclusive

@Test(groups = { "fast", "database"}) @Test(groups = { "slow", "database" })

  • Use regular naming pattern for groups

@Test(groups = { "os.linux.debian" })

QCon, San Francisco

@Test(groups = { "os.linux.debian" })

@Test(groups = { "database.table.ACCOUNTS" }) @Test(groups = { "database.ejb3.connection" })

  • TestNG has the ability to parse regular expressions to locate the

groups you want to run

  • running the groups "database.*" will run all the database tests
  • or narrow down the set of tests to "database.ejb3.*"
slide-12
SLIDE 12
  • Groups

→ Data Providers

QCon, San Francisco

→ Data Providers

  • Dependent tests
slide-13
SLIDE 13

Data Providers

  • Data Providers allow you to separate

data from the logic of your tests

  • Data can come from Java, flat file,

QCon, San Francisco

  • Data can come from Java, flat file,

database, network, etc…

  • You can have as many Data Providers

as you want (e.g. “string-provider”, “url- provider”, etc…)

slide-14
SLIDE 14

What makes a Data Provider?

  • Use the @DataProvider annotated a

method with @DataProvider

  • Method must return Object[][]

QCon, San Francisco

  • Method must return Object[][]
  • Name the data provider to be used by

your test method:

@Test(dataProvider=“clusters”)

  • TestNG will handle the type conversions
slide-15
SLIDE 15

@DataProvider example

Directory made of .properties file: cluster1.properties, cluster2.properties, etc…

QCon, San Francisco

etc… Property file example: (host=port) 169.1.3.2=6552 169.5.12.3=2002

slide-16
SLIDE 16

@DataProvider Example

@Test(dataProvider=”hosts") public void verifyHost(Properties settings){ Enumeration keys = settings.keys(); while (keys.hasMoreElements()) {

QCon, San Francisco

String host = settings.keys.nextElement(); String port = settings.getProperty(host); // perform test on host/port } }

slide-17
SLIDE 17

@DataProvider Example

@DataProvider(name = “hosts”) public Object[][] loadHosts() { File rootDir = new File("root"); String[] names= rootDir.list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".properties"); QCon, San Francisco } }); Object[][] result = new Object[names.length][]; for(int i= 0; i < names.length; i++) { Properties prop = new Properties(); prop.load(new FileInputStream(new File(rootDir, names[i]))); result[i] = new Object[] {prop}; } return result; }

slide-18
SLIDE 18
  • Groups
  • Data providers

QCon, San Francisco

  • Data providers

→ Dependent tests

slide-19
SLIDE 19

Method dependency

  • Problem:

– certain test methods depend on the success of previous methods – you don't want to duplicate your efforts while writing tests

QCon, San Francisco

  • Example: DAO testing:

– One method to launch the server: embedded DB/connect to DB – One test method to test if the table to work on is available – Methods to verify functionality insert(), findById(), update(), delete()

slide-20
SLIDE 20

Example

public class DaoTest { @BeforeMethod initConnections() {} @Test public void insert() {} @Test public void findById() {} @Test public void deleteById() {}

QCon, San Francisco

@Test public void deleteById() {} } Problems:

  • initConnections() fails
  • 4 FAILURES
  • What we want: 1 FAILURE, 3 SKIPS
slide-21
SLIDE 21

Example

public class DaoTest { MyDao dao; @BeforeClass public void initConnections() {} @Test public void isSetupOk() { assert dao.getConnection() != null; } QCon, San Francisco @Test(dependsOnMethods={"isSetupOk"}) public void insert() {} @Test(dependsOnMethods={"insert"}) public void findById() {} }

Problems:

  • Doesn’t scale very well
  • Breaks if you refactor
slide-22
SLIDE 22

Example

public class DaoTest { @BeforeClass public void initConnections() {} @Test(groups= "prepare") public void isSetupOk() { assert dao.getConnection() != null; // ... }

QCon, San Francisco

@Test(groups="create", dependsOnGroups="prepare") public void insert() {} @Test(groups= "retrieve", dependsOnGroups = "create") public void findById() {} } Benefits:

  • Method names can change
  • Easy to add future test methods
slide-23
SLIDE 23

What groups give you

  • a way to order methods;
  • order not just individual methods, but

collections of methods grouped logically

QCon, San Francisco

collections of methods grouped logically

  • a mechanism to accurately report

failures due to failed dependency

  • a way to exactly reproduce the failure

scenario

slide-24
SLIDE 24

Conclusion

  • Groups, Data Providers and Dependent

Tests are very popular features

QCon, San Francisco

  • TestNG has many more features, see

for yourself!

http://testng.org

slide-25
SLIDE 25

Designing for Testability

QCon, San Francisco

slide-26
SLIDE 26

Do we need to design for testability? Unfortunately, yes!

QCon, San Francisco

Unfortunately, yes! Requires forethought and giving up on certain ideas

slide-27
SLIDE 27

What’s so hard about testing?

QCon, San Francisco

What’s so hard about testing?

slide-28
SLIDE 28

Identifying the enemy

Statics! In all shapes: singletons, global variables, static fields

QCon, San Francisco

variables, static fields Extreme encapsulation

slide-29
SLIDE 29

Enemy #1 : Statics

Hard to test: void f() {

QCon, San Francisco

void f() { Database db = Database.getInstance(); db.query("DELETE FROM ACCOUNTS"); }

slide-30
SLIDE 30

Statics

Better void f(Database db) {

QCon, San Francisco

void f(Database db) { db.query(”…”); }

slide-31
SLIDE 31

Statics

Product: db = Database.getInstance();

QCon, San Francisco

f(db) Test: db = new Mock(Database.class); f(db);

slide-32
SLIDE 32

Even better

Use a dependency injection framework! Highly recommended: Guice ("juice"), by Bob Lee.

QCon, San Francisco

void f(@Inject Database db) { db.query("..."); } Spring also an option

slide-33
SLIDE 33

Enemy # 2: Extreme encapsulation

Everything private and final

QCon, San Francisco

Reasonable from an OO perspective Adversely impacts testing

slide-34
SLIDE 34

Questioning existing practices

Beware of certain design patterns such as Singleton or Abstract Factory

QCon, San Francisco

Singleton or Abstract Factory It's okay to open up a class to make it more testable (package protected is your friend!)

slide-35
SLIDE 35

And now…

The big elephant in the room…

QCon, San Francisco

Test-Driven Development!!!

slide-36
SLIDE 36

Test-driven development

Show of hands: Who…

QCon, San Francisco

Who… 1) Writes tests first most of the time? 2) Writes tests last most of the time? 3) Does a mix of both?

slide-37
SLIDE 37

TestNG and TDD

Perfect project for a TDD approach Yet, only ~10% of the tests I wrote were

QCon, San Francisco

Yet, only ~10% of the tests I wrote were developed using TDD Is it just me?

slide-38
SLIDE 38

Problems with TDD

Promotes micro-design over macro-design Hard to apply in practice

QCon, San Francisco

Hard to apply in practice No clear evidence that it produces better designs than "tests last"

slide-39
SLIDE 39

TDD promotes micro-design

Focuses on the immediate problem at hand

QCon, San Francisco

"Simplest thing that could possibly work" can lead to short-sighted designs Risk of churn (throw-away code)

slide-40
SLIDE 40

TDD is hard to apply in practice

Forces you to a design that might be good for testing but not optimal for your users (or even yourself)

QCon, San Francisco

yourself) Makes you spend a lot of time with compilation and IDE errors (negates IDE benefits) Counter-intuitive

slide-41
SLIDE 41

TDD: good or evil?

Great to train junior programmers or non- test savvy developers

QCon, San Francisco

test savvy developers Not so great for more experienced developers

slide-42
SLIDE 42

Conclusion

When in doubt, remember that tests are for users, not for developers

QCon, San Francisco

Be open to giving up on some established software engineering practices Don't feel bad if you're not using TDD

slide-43
SLIDE 43

One last thing:

QCon, San Francisco

Available from Amazon.

slide-44
SLIDE 44

Thank you for your attention!

QCon, San Francisco

Questions?