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).
Related
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
This is more of a question on test automation framework design. Very hard indeed to summarize whole question in one line :)
I am creating a test automation framework using Selenium. Mostly I am accessing the data (methods name) from an excel file.
In my main Runner class I am getting a list of test cases. Each test case has a set of methods (can be same or different) which I have defined in a java class and executing each method using java reflection api. Everything is fine till this point.
Now I want to incorporate TestNG and reporting/logging in my automation suite. Problem is I cant use #Test for each method as TestNG considers #Test = 1 Test Case - but my 1 Test case might have more than 1 methods. My methods are more like a test steps for a test case, reason is I dont want repeat the code. I want to create a #Test dynamically calling different sets of methods and executing them in Java Or defining each teststeps for a #Test. I was going through the TestNG documentation, but could not able to locate any feature to handle this situation.
Any help is really appreciated and if you have any other thoughts to handle this situaton I am here to listen.
Did you try the following?
#Test(priority = 1)
public void step1() {
//code
}
#Test(priority = 2)
public void step2() {
//code
}
You need to use "priority" for each method, otherwise it won't work.
I'm looking for the ability to nest JUnit tests. I found #RunWith(Enclosed.class), but it only runs one level inclosed and other tests aren't run.
Never mind, I found the answer over here: NitorCreations Nested Runner
This is exactly what I was looking for. It allows JUnit tests to be fully nested.
Because NestedRunner tests did not properly visualize test names in my IntelliJ IDEA I am using HierarchicalContextRunner instead
It provides exactly the same functionality. Just swap them in the #RunWith if you are not happy with how your IDE is showing your tests.
Here is an example of what was wrong:
#RunWith(NestedRunner.class)
public class ATest {
#Test
public void haveARegularTestsInside() {}
public class hasASubClass {
#Test
public void thatHasTests() {}
}
}
looks like this:
Here I expected to have thatHasTests at the last line, but got the whole AClass$hasASubClass.thatHasTests.
change #RunWith to HierarchicalContextRunner and what you get is now this:
Better, isn't it?
I have a very strange problem, when i try to run a JUnit test with multiple test case, it will only pass the first test case and shown IndexOut of Bound error
public class ABCTest {
#Test
public void basicTest1(){...}
#Test
public void basicTest2(){...}
...
but if i commend the rest test case, test them one by one, it will pass all of them.
public class ABCTest {
#Test
public void basicTest1(){...}
//#Test
//public void basicTest2(){...}
//...
Since you do not provide the complete testcase and implementation class, I have to make some assumptions.
Most likely you are mutating the state of the tested object by the testcase.
Usually you try to get a clean test fixture for each unit test. This works by having a method with the #Before annotation which creates a new instance of the class under test. (This was called 'setUp()' in older versions of junit.)
This ensures that the order of test method execution as well as the number of executions does not matter and each method is working isolated.
Look at what you are doing inside of the test case and see if you are changing data that may be used by the other test cases and not restoring it to the original state. For example you have a text file that you read and write to in basicTest1 that you then read again in basicTest2 but assume the file is the same as it was before you ran basicTest1.
This is just one possible problem. would need to see the code for more insight
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.