Friday, August 21, 2015

TestNG - Notes and Support

Detailed info:

http://testng.org/doc/documentation-main.html



Presention that makes you understand TestNG better and differentiates from Junit:

source: http://kaczanowscy.pl/tomek/sites/default/files/testng_vs_junit.txt.slidy_.html#(24)

 Why TestNG?
My (biased) observations
People are moving from JUnit to TestNG once they start to write integration and end-to-end tests (e.g. with Selenium). Apparently, on unit tests level you can put up with JUnit deficiencies, but once you go outside the unit tests realm, JUnit stands in your way.
From what I have noticed, people who work with JUnit usually test their code with only one set of parameters. I suspect this is because parametrized tests are unusable with JUnit. And this is bad, because such tests are really useful.
If you really, really have to use JUnit (do you?) then at least us JUnit Params!
Parametrized tests
Parametrized tests
@DataProvider
private static final Object[][] getMoney(){
    return new Object[][] {
        {new Money(4, "USD"), new Money(3, "USD"), 7},
        {new Money(1, "EUR"), new Money(4, "EUR"), 5},
        {new Money(1234, "CHF"), new Money(234, "CHF"), 1468}};
}

@Test(dataProvider = "getMoney")
public void shouldAddSameCurrencies(Money a, Money b,
        int expectedResult) {
    Money result = a.add(b);
    assertEquals(result.getAmount(), expectedResult);
}
Parametrized tests
@DataProvider
private static final Object[][] getMoney(){
    return new Object[][] {
        {new Money(4, "USD"), new Money(3, "USD"), 7},
        {new Money(1, "EUR"), new Money(4, "EUR"), 5},
        {new Money(1234, "CHF"), new Money(234, "CHF"), 1468}};
}

@Test(dataProvider = "getMoney")
public void shouldAddSameCurrencies(Money a, Money b,
        int expectedResult) {
    Money result = a.add(b);
    assertEquals(result.getAmount(), expectedResult);
}

@DataProvider
private static final Object[][] getInvalidAmount(){
    return new Integer[][] {{-12387}, {-5}, {-1}};
}

@Test(dataProvider = "getInvalidAmount", expectedExceptions = IllegalArgumentException.class)
public void shouldThrowIAEForInvalidAmount(int invalidAmount) {
    Money money = new Money(invalidAmount, VALID_CURRENCY);
}

@DataProvider
private static final Object[][] getInvalidCurrency(){
    return new String[][] {{null}, {""}};
}

@Test(dataProvider = "getInvalidCurrency", expectedExceptions = IllegalArgumentException.class)
public void shouldThrowIAEForInvalidCurrency(String invalidCurrency) {
    Money money = new Money(VALID_AMOUNT, invalidCurrency);
}
Test Fixture Setting
@Test
public class TestFixtureTest {

    private Server server;
    private Client client;

    @BeforeSuite(timeOut = 1000)
    public void setUpServer() {
        server = new Server();
        server.start();
    }

    @BeforeMethod
    public void setUpClient() { client = new Client(); }

    // some test methods here

    @AfterSuite
    public void shutDownServer() { server.stop(); }
}
Logical dependencies gives you a much more realistic error information - you learn that 1 tests has failed and 99 has been skipped, which is much easier to fix than the information about 100 failed tests (OMG! what’s going on!? All tests failed…. aaarrhghg!).
Dependencies between tests
@Test
public void serverStartedOk() {}

@Test(dependsOnMethods = { "serverStartedOk" })
public void method1() {}
Dependencies between tests
@Test(groups = { "init" })
public void serverStartedOk() {}

@Test(groups = { "init" })
public void initEnvironment() {}

@Test(dependsOnGroups = { "init.* })
public void method1() {}
Listeners, Reporters
OK       FirstTest           fifthTestMethod            1944
OK       FirstTest           firstTestMethod            3799
OK       FirstTest           fourthTestMethod           1920
OK       FirstTest           secondTestMethod           4891
OK       FirstTest           thirdTestMethod            2963
OK       SecondTest          methodA                    3525
OK       SecondTest          methodB                    1390
FAILED   SecondTest          methodC                     117
SKIPPED  SecondTest          methodD                      23
OK       SecondTest          methodE                    4552
There is more of this
Who is the boss?
JUnit
TestNG
releases since 2009 (not counting betas)
3 - from 4.8.2 to 4.10 (see JUnit announcements)
13 - from 5.12 to 6.4 (see TestNG Changelog)
mailing list
JUnit mailing list,
members: 8511
emails since January 2012: ~25
TestNG mailing list,
members: 2858,
emails since January 2012: ~560, threads: 115
While better support for integration and end-to-end tests is definitely true, not many people know that TestNG offers more than JUnit also in case of unit tests.

Concurrency
No need to create own Thread objects! Use annotations and that is it!
An example of running same test method simultaneously (20 times, by 3 threads):
@Test(threadPoolSize = 3, invocationCount = 20)
public void concurrencyTest() {
    System.out.print(" " + Thread.currentThread().getId());
}
Result:
13 12 13 11 12 13 11 12 13 12 11 13 12 11 11 13 12 11 12 13


Parametrized tests
In general, it is a good practice, to test your code with different sets of parameters:
§  expected values: sqrt(4), sqrt(9),
§  boundary values: sqrt(0),
§  strange/unexpected values: sqrt(-1), sqrt(3)
A good testing framework should make it simple, and avoid copy&paste coding.
Alas, the default JUnit implementation of the parametrized tests is rather unusable… In short, JUnit expects all test methods to be parameter-less. Because of this constraint, parametrized tests with JUnit looks awkward, because parameters are passed by constructor and kept as fields!
You can see some examples here, here or here.



Parametrized tests are very simple with TestNG (no constructor awkwardness).
You can have as many data providers in one class as you wish. You can reuse them (call them from other classes), and you can make them "lazy", so each set of parameters is created when required.
Once you migrate to TestNG you will notice that you start writing a lot of parametrized tests. Because they are so very useful!


Ok, so this is how it looks with TestNG. There is a test method (shouldAddSameCurrencies()) which has some "testing logic" and a data provider method (getMoney()) which provides data. That is all.





Parametrized tests
You also get a very detailed information about the test results (in this case thanks to reasonable implementation of Money class toString() method), e.g.:

BTW. not sure if you noticed, but parametrized tests are perfect for verifying if all your "utils" methods work - you know, all this date/strings/numbers handling/transforming methods.


TestNG does not care how many parametrized tests you have in one class. See below for an example ofMoneyTest which verifies both the constructor and add() method using data providers.


TestNG offers well-thought @Before… and @After… annotations (on suite, class, group and method level).
An example below shows that a server (something heavy) is created only once before a test suite, and client (something small and cheap to create) is created before each test method.


Parameters passing
Want to:
§  configure your tests so they e.g. invoke GUI methods on different servers/ports?
§  run tests using mysql database instead of h2?
§  run GUI tests with Opera, Firefox, Chrome (or even IE 6)?
It is pretty simple to pass parameters to test methods (example copied directly from TestNG documentation):
@Parameters({ "datasource", "jdbcDriver" })
@BeforeMethod
public void beforeTest(String ds, String driver) {
    m_dataSource = ...;
    m_jdbcDriver = driver;
}
Parameters can come for example from configured Maven Surefire Plugin


Groups of tests
§  each test class (and method) can belong to multiple groups,
§  it is pretty easy to run only selected group:
·         e.g. you can run only tests from groups "smoke", or only "gui" tests,
·         it is possible to define dependencies between methods/groups (see next slide).
§  all done with annotations (e.g. @Test(groups = "smoke"))
This is also supported by tools - e.g. it is pretty simple to instruct Maven to do it (see here).


Dependencies between tests
Rather bad practice with unit tests,
but very important for integration and end-to-end tests, e.g.:
§  fail fast:
·         run Selenium tests only if application was deployed properly,
·         run full system tests only if smoke tests passed,
§  logical dependencies between tests:
·         execute shouldDeleteUserFromDatabase test only if shouldAddUserToDatabaseworked
Fail fast means that the feedback will be much quicker in case of failed tests.


Example copied from TestNG documentation.
Method method1 will be skipped (will not run) if serverStartedOk fails.


Example copied from TestNG documentation.
Method method1 will be skipped (will not run) if any method of group init fails.



It is pretty easy to write your own listeners (which act in runtime) and reporters (which are invoked after the execution).
Example output of listener which prints test result, class and method name, and execution time of each test method:
This feature is not very useful with unit-tests but can be very handy to report progress/results of integration and end-to-end tests.



There are few more interesting features of TestNG (e.g. factories) but lets skip it.




(chart from Google trends)
Well, as you can see TestNG is not really closing the gap. It rather seems to find its niche and sit there. Well, it is time to change it! :)



But who is the boss now?
All data gathered on 4th April 2012.
One could say, this all means only that JUnit development has been finished, all documentation has been written, all questions answered and easy to find by googling, all issues solved, … well, actually no. It rather looks, hm… a little bit abandonned.


Documentation
§  TestNG offers much better documentation
·         even though there are numerous articles about different versions and features of JUnit you will find it hard to find a comprehensive resource on the net which explains it thoroughly.
·         TestNG documentation is in very good shape, and always up-to date (seriously, it is!)


Have no fear
Yes, with TestNG you still can:
§  run tests with Maven, Ant, Gradle, …
§  execute tests with your IDE: Eclipse, IntelliJ IDEA, …
§  enjoy Spring support for testing,
§  etc., etc.



How to migrate from JUnit to TestNG?
§  There is Eclipse converter which does a decent job of changing imports etc. so you do not have to do it by hand
§  TestNG plugin for IntelliJ IDEA also provides a "Convert JUnit test to TestNG" feature
§  There might be an issue with objects creation, because TestNG does not create test classes before every test
·         This means you need to enclose creation of objects within some method.
§  Another - minor - issue is with assertions, because TestNG uses different order of arguments (first actual, then expected) than JUnit (first expected, then actual)
·         If you use matcher libraries, you do not have to change anything



The End
Great things are done by a series of small things brought together.
— Vincent Van Gogh
It is many small things which sum up and give you a much better experience.
TestNG offers support for all kind of tests. It is great, and still getting better with each new release.
…is TestNG a silver bullet? No, but close to it. :)
P.S. Want to know more about TestNG? Read the book.




List of Annotations:

@Beforesuite
You can set driver paths (System.setProperty(...)) in@BeforeSuite method. 
@BeforeMethod
Instantiate browser in @BeforeMethod.


JUnit vs TestNG

8/21/15

Source: http://technologyandleadership.com/junit-vs-testng-core-differences/

junit vs TestNG – core differences


Junit and TestNG differ in the core design. Junit is a unit testing framework while TestNG addresses testing at a higher level. This article discusses the three main differences between TestNG and Junit.
1.     In Junit, one test case failure can cause a bunch of test cases to fail in the test suite. There is no option of skipping the set of dependent test cases. The dependent test cases are also reported as failures. For example, suppose there is a test case to test login and the next 10 test cases need to perform a transaction after login. If the login test case fails the other 10 test cases will also fail.
TestNG handles dependency between test cases. If one test case failure causes the failure of a group of test cases it skips that group and executes the rest of the test suite. The group that has dependency on the failed test cases is reported as skipped NOT failed.
2.     In TestNG groups can be defined. Groups are specific subsets of the test suite. We can choose to run only specific subset of the testsuite say database related test cases instead of running the entire test suite. This can be done as below:
In the test case we define two groups DBTestcase and deprecated as below:
@Test(groups = {"DBTestcase", "deprecated"})
public void testMethod2()
{
 
}
In TestNG.xml config file we write the below piece of code to include only database related test cases and exclude the deprecated ones.
<test name="Sample">
 <groups>
  <run>
   <include name="DBTestcase" />
   <exclude name="deprecated" />
  </run>
 </groups>
 <classes>
  <class name="example1.Test1" />
 </classes>
</test>
In Junit for a long time it was not possible to run a specific subset of the test cases. We can either run the entire suite or run each test case individually. Junit 4.8 introduced a new feature called “Categories” to overcome this limitation. However groups are much easier to configure in TestNG.
3.     TestNG supports parameterization for objects. For example I can execute a single test case for multiple test data sets through the parameterization of DataProvider object. This makes the implementation of data driven testing more flexible in TestNG as below:
@DataProvider(name = "DP1")
public String[][] testData() throws Exception
{
String[][] sdataArray = {{"james","moosecat$", "james@gmail.com","selenigr","selenigr1$", "selenigr@yahoo.co.uk"}};
return sdataArray;
}
 
@Test (dataProvider = "DP1")
public void evernoteSharing(String user1, String password1, String email1, String user2, String password2, String email2)
{
 
}
In junit test data is not parameterized using a DataProvider hook. Data-driven testing is implemented differently and involves more coding.