How do I re-use (include) Junit test block in other tests - java

I am fairly new to the JAVA world - coming from a ColdFusion background - and have been learning Java because I'm learning Selenium WebDriver /JUnit. I have written several test classes that test admin functionality that follow a similar structure.
public class myclass{
public static WebDriver driver;
#BeforeClass
public static void startDriver(){
driver = new FirefoxDriver();
driver.get("some url");
}
#Test
public void myLogin(){
some login code
}
#Test
public void somefunction() {
other admin function to test
}
My question is this - since all my tests require the user to log in - I end up having to re-use the "mylogin" test code over and over. How can I write the tests to simply "include" (like the "cfinclude" tag in ColdFusion) the login code so that if changes are made to the login page functionality - I only have to change it in one place.

Java hasn't got a lexical include statement like ColdFusion or C. This is by design, because just pasting sourcecode before compilation is a very unclean way of sharing code between modules.
But there are many other ways to approach this issue. Here are two:
Create your own library with commonly used functionality encapsulated in methods and use this library in your tests
Add setUp and tearDown methods for your test classes. These methods are executed before and after each one of your test methods. Note that test classes can inherit from each other. So when you have lots of test classes with identical setUp and tearDown methods, you can make them extend a common base class and implement these methods in the base class once.

You can implement the myLogin() functionality in a base parent class what you will need to extend in all of your test classes to access this functionality across various tests:
public abstract class MyBaseTest {
public void myLogin() {
<some login code>
}
}
public class MyClass extends MyBaseTest {
#Test
public void somefunction() {
super.myLogin();
}
}

You could use the #Before annotation to accomplish this. The annotated method will run before every #Test annotated method. Similarly you could use #After to logout after every unit test, if needed.

Related

How to reuse method and test in JUnit?

I've tried to avoid duplicate code in JUnit test, but I'm kind of stuck.
This is my first test, for the second one it has exactly the same methods but different service (different input). instead of the TestCaseResourceTest1 I have TestCaseResourceTest2. Now what could be the proper way to test both? I want to have a separate file for test number 2, how should I avoid the duplicate code? (ex. use the beforeFileTest() method)
public class TestCaseResourceTest1 {
#Mock
private TestService testService;
#Mock
private AreaService areaService;
private TestCaseService1 testCaseService1; // is changed in test2
#Before
public void before() throws Exception{
testCaseService1 = mock(TestCaseService1.class); // is changed in test2
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
private void beforeFileTest() throws Exception{
doReturn(true).when(areaService).chechExists(any(String.class), eq(false));
}
#Test
public void verifyFileExists() throws Exception{
verifyOtherArea(testCaseService1); // is changed in test2
doReturn(false).when(areaService).chechExists(any(String.class), eq(false));
}
}
just lines with comment is changed in test2 are differences.
Tnx
Given this excerpt from your question:
… instead of the TestCaseResourceTest1 I have TestCaseResourceTest2 … I want to have a separate file for test number 2
… the standard ways of sharing code between test cases are:
Create a Test Suite and include the shared code in the test suite (typically in #BeforeClass and #AfterClass methods). This allows you to (1) run setup code once (per suite invocation); (2) encapsulate shared setup/teardown code and (3) easily add more tests cases later. For example:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestCaseResourceTest1.class,
TestCaseResourceTest2.class
)}
public class TestSuiteClass {
#BeforeClass
public void setup() {
beforeFileTest();
}
private void beforeFileTest() throws Exception {
// ...
}
}
Create an abstract class which parents TestCaseResourceTest1 and TestCaseResourceTest2 and let those test cases call the shared code in the parent (typically via super() calls). With this approach you can declare default shared code in the parent while still allowing sub classes to (1) have their own behaviour and (2) selectively override the parent/default behaviour
Create a custom JUnit runner, define the shared behaviour in this runner and then annotate the relevant test cases with #RunWith(YourCustomRunner.class). More details on this approach here
Just to reiterate what some of the other posters have said; this is not a common first step so you may prefer to start simple and only move to suites or abstract classes or custom runners if your usage provides a compelling reason to do so.
I had the such situation and it was a sign about wrong implementation design. We are talking about pure unit tests where we test exactly what is implemented in the production classes. If we need duplicated tests it means we probably have duplication in implementation.
How did I resolve it in my project?
Extracted common logic into parent service class and implemented unit tests for it.
For child services I implemented tests only for particular implemented code there. No more.
Implemented an integration tests on real environment were both services were involved and tested completely.
Assuming you want to have the exact same test run for 2 different classes (and not mocking it as in your example code), you can create an abstract test class, that has abstract method that returns an instance of the class to be tested.
Something in the vein of:
public abstract class TestCaseResourceTest {
protected abstract TestCaseService1 getServiceToTest();
#Before
public void before() throws Exception {
testCaseService1 = getServiceToTest();
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
#Test
public void test() {
// do your test here
}
}
public class ConcreteTest extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new TestCaseService();
}
}
public class ConcreteTest2 extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new DifferentService();
}
}
Have you considered using JUnit 5 with its http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests ?
It allows you to re-use your tests with different input. This is an example from the documentation which illustrates what you can do now with JUnit 5:
#ParameterizedTest
#ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
But you can also create your methods which return the input data:
#ParameterizedTest
#MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
Here I am using just strings, but you can really use any objects.
If you are using Maven, you can add these dependencies to start using JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0-RC2</version>
<scope>test</scope>
</dependency>
The only annoying thing about JUnit 5 is that it is not released yet.
When going from one test to two tests, you don't know what will be duplicate code, so I find it useful to put everything into one test method. In this case, start by putting the contents of the #Before and beforeFileTest methods inline in the test.
Then you can see that it is just te service that needs changing, so you can extract everything except that into a helper method that is called from two tests.
Also, after you have two tests that are calling the same helper method and are happy with that test coverage, you could look into writing parameterized tests. For example with JunitParams: https://github.com/Pragmatists/junitparams/wiki/Quickstart

getting TestNG to treat class variables like JUnit with Guice

I am trying to setup TestNG so that it gives me new instances of my class variable for each test (basically like JUnit). I need this as I intend to parallelize my tests at the method level. I have been experimenting with both standalone Guice and the built in Guice functionality that TestNG provides to try to accomplish this but I have had no luck. I know that I can use ThreadLocal, but calling .get() for every variable in the test is pretty unappealing. I am weary of using GuiceBerry as it does not really have a lot of updates/activity and it's last release is not even acquirable via Maven. I am pretty set on TestNG as for all the inconvenience this is causing me it still does a lot of great things. I am open to things other tools though to accomplish my goal. Basically I want things setup so the below tests would work consistently. Any help would be greatly appreciated.
// just has a variable thats a class called child with a simple string variable
// with a value of "original
Parent p;
#Test
public void sometest1(){
p.child.value = "Altered";
Assert.assertTrue(p.child.value.equals("Altered"));
}
#Test
public void sometest2(){
Assert.assertTrue(p.child.value.equals("original"));
}
TestNG doesn't create a new instance for each test. If you want such a behavior than I recommend creating separate test classes. e.g.:
public class SomeTest1 {
Parent p;
#Test
public void something(){
p.child.value = "Altered";
Assert.assertTrue(p.child.value.equals("Altered"));
}
}
public class SomeTest2 {
Parent p;
#Test
public void something(){
Assert.assertTrue(p.child.value.equals("original"));
}
}
Note that TestNG can run JUnit 3 and JUnit 4 tests (you might maintain a mixed suite depending on the style you want to use in a given test class).

Junit 4 how to initialize in test suite and pass it to test classes

Is there a way in Junit4 to pass some pre-initialized data like http connections that you initialize using say '#ClassRule' in the class annotated with '#RunWith(Suite.class)' to all child (i.e. suite) test classes? Also how to ensure that the classes in the suite cannot be run individually?
e.g.
class A {
private HttpClient client;
#Test
public void someTest() {
client.execute(...);
...
}
}
#RunWith(Suite.class)
#Suite.SuiteClasses({A.class})
public class Suite {
private static HttpClient client;
#ClassRule
public static ExternalResource resource= new ExternalResource() {
#Override
protected void before() throws Throwable {
client = new DefaultHttpClient();
}
}
Thanks,
Paddy
I don't think that you can achieve that with JUnit.
The only possibility I see is to use an abstract class and inherit that one in every test class.
public abstract class AbstractTest {
#ClassRule
public static ExternalResource resource= new ExternalResource() {
//...
}
}
public class MyTest extends AbstractTest {
}
Also how to ensure that the classes in the suite cannot be run individually?
I don't think that is possible either.
But why would you want that?
After fixing a single failing test, do you really want to re-run all tests to check if one test is working?
(Of course, the fix could have introduced side effects but you can re-run all tests when you know that your fixed test is working.)
Moreover, the tests should be able to run independently.
When you're using the out-of-the-box Runners of JUnit you would get any access from a test Suite to its child tests. Instantiation of the test classes is done internally in the framework.
If you want to pass information/state from one test to another, I'd suppose to implement some kind of "context". E.g. a Singleton with a static Getter and Setter for the context that allows your suite to store an Object and to read it later on from your tests.

Extending from Suite Runner vs BlockJUnit4Runner while defining some TestRules

I have a requirement to write many tests. I have extended Suite Runner of JUnit in order to be able to add new annotations where I can mention several Prerequisite classes which will be executed before any of the tests or setups get executed. My Typical test looks like this.
#RunWith(CustomSuiteRunner.class)
#BeforeSuite(Prerequisite.class)
#AfterSuite(CleanupOperations.class)
#Suite.SuiteClasses({
SimpleTests.class,
WeatherTests.class
})
public class SimpleSuite {
}
I have overridden public void run(final RunNotifier notifier) to add code the required code to trigger prerequisites and cleanup operations mentioned in BeforeSuite and AfterSuite annotation.
Now, I'm trying to find out how I can achieve the same by extending BlockJUnit4Runner? I can't find any method equivalent to run that starts the execution to override the behaviour. There is runChild which gets triggered before a child gets executed.
The reason I'm looking for this is I'm trying created several rules in an Interface and make my tests implement that so that they will be available, however as Interface elements are static and final JUnit is ignoring these. In another Question I asked today I got answer that I can make JUnit consider rules mentioned in an Interface by extending BlockJUnit4Runner and overriding getTestRules().
So, Here is what I'm trying find out.
Is it possible to extend BlockJUnit4Runner to make it take a list of tests and run them as suite and also run some code before any tests get execute and after all tests are executed?
How can I extend Suite Runner to consider TestRules defined in an implemented interface?
It is pretty much possible to extend BlockJUnit4Runner and make it take a list of tests and run them as suite with required test dependencies handled within the extended runChild() method
public class CustomRunner extends BlockJUnit4ClassRunner {
private List<String> testsToRun = Arrays.asList(new String[] { “sample1” });
public CustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
public void runChild(FrameworkMethod method, RunNotifier notifier) {
//Handle any dependency logic by creating a customlistener registering notifier
super.runChild(method,notifier);
}
}

Re-using login functionality in Selenium page object model tests

I am exploring the use of Selenium 2 on a web application which requires authentication before a user can use any of the application. I am planning on either JUnit 4 or TestNG (Still investigating which one to use with Grid 2). I may plan to use jbehave as well.
Does anyone have any suggestions on how I can improve the following test so I can use successful login functionality across all my tests? I want to avoid duplicating login in the tests itself.
public class LoginPageTest {
private LoginPage page;
#Before
public void openTheBrowser() {
page = PageFactory.initElements(new FirefoxDriver(), LoginPage.class);
page.open("http://www.site.com/Login");
}
#After
public void closeTheBrowser() {
page.close();
}
#Test
public void whenTheUserEntersValidCredentialsTheUserIsLoggedIn() {
assertThat(page.getTitle(), containsString("Login") );
}
}
The test is simplified but it will return a page object of a successful login.
thanks
check case study # http://blog.infostretch.com/?p=806 for better idea. If you are at initial level of development i would suggest you to try using QAF (formerly ISFW).
Your best option might be to use the LoginPageTest class as a parent class and extend each of your test classes from LoginPageTest.
That way, each test can login to the system using the parent's setup and tear down methods and do its own additional testing as well.
Create Libraries and call the sequence of test cases to execute one test case/scenario.
Eg:
lib.login();
lib.whenTheUserEntersValidCredentialsTheUserIsLoggedIn();
lib.logout();
for doing this take care of object creations. solution for object is use of super eg: super.login()

Categories