This week I had to rewrite a bunch of functional tests, mostly
Selenium stuff. When I think about
Java Unit tests the first thing that comes to my mind is the
JUnit framework. All tests that I have written until past week were with JUnit, and
was using it to run Selenium.
But I got one more requirement, since I was rewriting all tests I would like to change environments (development and pre-production) without dealing in the code where was running the tests. The problem was a simple one, just write configurations with URLs, expected values and so on, for each of my environments. A trivial example is using different URLs in selenium for the same tests. Well, how do this with JUnit?
First approach, using JUnit 3In JUnit 3 (old one) you have
Test Suites. Programatically you have a chance to read a properties file and give the information to your test classes. Well, this could work if I had not the principle:
"Do not write test code if isn't a test." When I caught myself creating a "little" framework to test my application I realized "I'm in the wrong way". Not that you should never code a "little" framework to simplify even more the tests, but i hadn't the time to do it.
Second approach, using JUnit 4Well, JUnit 4 is more flexible, newer and uses annotations; and I didn't explored it well. After some digging i found JUnit's
Parameterized Tests, but again I had (bear with me in this one) "to code, code to test code". And one more thing, JUnit 4 have
Test Suites but, AFAIK, you only have a annotation version to define the classes for a suite.
JUnit wasn't solving the problemAfter some thought i had two choices, forget about environments, or spend some time coding new stuff that wasn't tests or my application. Justice has to be made, JUnit is a excellent test framework but I think my objectives weren't too "Unitwise".
TestNG, next generation?I heard about
TestNG about a year ago and didn't gave it enough attention, I was happy with JUnit. But, everyday is a new day and I had a problem, so I started to read about TestNG. I was skeptic at first, thinking "maybe this can do it, but I don't have time to learn it all". I was wrong, happily wrong.
TestNG, next generation!I have to confess, there's nothing to write here, maybe just some code. Remember the problem? "Two environments, one test, test it all". First, let me show the test example.
package com.keepcoding.test;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.*;
import com.thoughtworks.selenium.*;
public class Google {
private Selenium selenium;
@BeforeClass
@Parameters({"selenium.host","selenium.port","selenium.browser","selenium.url"})
public void startSelenium(String host, String port, String browser, String url) {
this.selenium = new DefaultSelenium(host, Integer.parseInt(port), browser, url);
this.selenium.start();
this.selenium.open(url);
}
@AfterClass(alwaysRun=true)
public void stopSelenium() {
this.selenium.stop();
}
@Test
@Parameters({"search","expected"})
public void googling(String search, String expected) {
try {
selenium.type("name=q", search);
selenium.click("name=btnG");
selenium.waitForPageToLoad("3000");
assertTrue(selenium.isTextPresent(expected));
} catch (SeleniumException e) {
fail(e.getMessage());
}
}
}
This is a simple test, will start Selenium, open a URL (to be defined), type something (to be defined) and finally check if a text is present. Some notes:
- @AfterClass is defined with "always=true" because Selenium has to stop, even on test a failure.
- Selenium commands are surrounded with a try/catch because I want to avoid ERROR statuses, better a FAILED status if Selenium fails.
Now let's look on TestNG configuration file:
Here I defined all parameters and what tests should run, as you probably guessed the test search on Google for "Keep Coding" and checks if this blog URL is in the results. The key thing is not the test itself, but it's setup. We have defined Selenium to open a certain URL and if we want change the URL is a simple case of editing the XML file.
Using Ant to test all environmentsFinally, how test all environments? First, create another TestNG configuration file, change the parameters accordingly, and use Ant to run it all. Here's a build file example:
This is a simple ant file, the highlighted part shows where you can have as much environments you want, for each one create a file changing parameters, skipping (not in production) tests and so on. TestNG will run one file after another for you.
ConclusionTestNG is really impressive, from very simple tests to complex environment tests, you have in hand a set of options to make it happen. When you mix TestNG with Selenium and Ant is possible to build very complex testing. TestNG goes beyond the "units" and provide what you need to think about "collections".