Customizing which tests to run with JUnit #Parameters? - java

I have the following code, where each url in listOne is tested with the method testItem:
#Parameters(name="{0}")
public static Collection<Object[]> data() throws Exception {
final Set<String> listOne = getListOne();
final Collection<Object[]> data = new ArrayList<>();
for (final String url : listOne) {
data.add(new Object[] { url });
}
return data;
}
#Test
public void testItem() {
driverOne.makeDecision(urlToTest);
assertTrue(driverOne.success(urlToTest);
}
What if I now wanted to add a second list, listTwo, and run a test method defined as follows on JUST the items of listTwo (but not listOne?)
#Test
public void testItemAlternate() {
driverTwo.makeDecision(urlToTest);
assertTrue(driverTwo.success(urlToTest));
}
That is, I want driverOne to make the decision for all URLs in listOne, and I want driverTwo to make the decision for all URLs in listTwo. What is the best way to translate this to code? Thanks.

Cited from: https://github.com/junit-team/junit/wiki/Parameterized-tests
The custom runner Parameterized implements parameterized tests. When running a parameterized test class, instances are created for the cross-product of the test methods and the test data elements.
Thus, I assume No, that's not possible.
If you want to do such a thing I guess that you either
(1) will need to construct two test classes one for each test to be executed with the first collection and one for each test to be executed with the second collection or
(2) will need to use another mechanism besides the #Parameters annotation, maybe hand-crafted.

You could include some test set identifier in your test set data itself, and then use the org.junit.Assume class to help:
#Test
public void testItem() {
org.junit.Assume.assumeTrue(testSetId.equals("TEST_SET_1"));
driverOne.makeDecision(urlToTest);
assertTrue(driverOne.success(urlToTest);
}
#Test
public void testItemAlternate() {
org.junit.Assume.assumeTrue(testSetId.equals("TEST_SET_2"));
driverTwo.makeDecision(urlToTest);
assertTrue(driverTwo.success(urlToTest));
}

As a completely different answer, there exists junit-dataprovider

Related

How can I access Objects within a void method while unit testing?

I am unit testing a Spring Boot service method. I have a void method with no args. It queries a db and gets a List. I can mock and assert on that. Then it runs through the list and changes object fields according to some condition. How can I check the contents of that list so I can assert on them?
#Transactional
public void someMethod() {
List<Person> myList = repository.findAllByAge(0);
myList.forEach(person -> person.setAge(18));
}
How can I assert on myList to check that each Person in myList with age 0 is getting set to age 18? I currently have this in my test class...
#Test
public void someMethod_withSuccess() {
List<Person> testList = new ArrayList<>();
testList.add(toPersonEntity(createPersonDto().setAge(0)));
when(mockRepo.findAllByAge(0)).thenReturn(testList);
mockService.someMethod();
}
You can call that method through Reflection API.
btw, if you need to test this method, it probably has to be redisigned to be public or not tested at all.
it is as easy as this
testList.forEach(person -> assertThat("person "+testList.indexOf(person),person.getAge(),equalTo(28)));

How to use datadriven test within #BeforeClass method in TestNG framework

Want to take urls one by one at #BeforeClass method and perform action in different #Test methods.
But #dataProvider only can used along with #Test method not with #BeforeClass in TestNG
constraint:-
Actually, All #Test method are independent on each other and So cant use single test method.
urls in #dataProvider is always be changing. We gets urls in run-time
How could we manage such scenarios ?
In short architecture of framework:-
#BeforeClass(dataProvider = "getTestUrls")
public void testPage(){
driver.get(testUrls);
}
#Test(priority=1)
#Test(priority=2)
#DataProvider
public Object [][] getTestUrls(){
return new Object[][] { { 1,"http://www.yahoo.com" }, {2,"http://www.google.com" } };
}
Use Factory method with dataProvider method ,
It create a multiple instance.
#Factory(dataProvider = "getUrls")
public SEOErrorFactoryResetBeforeClass(String pagUrl) {
this.pagUrl = pagUrl;
}
These constraints can be overcome by using data driven framework using POI jar files.
You can fetch the test urls from a excel file, data provider have some limitations.
Yes , #Factory annotation will solved your concern
#Factory(dataProvider = "getUrls")
public SEOErrorFactoryResetBeforeClass(String pagUrl) {
this.pagUrl = pagUrl;
}
Just use
context.getCurrentXmlTest().getParameters();
like this:
#SuppressWarnings("deprecation")
#BeforeClass
public void setUp(ITestContext context) {
System.out.println(context.getCurrentXmlTest().getParameters());
}

TestNG dataproviders with a #BeforeClass

I am trying to run a class with multiple tests under two different conditions. Basically I have a bunch of tests related to a search. I am adding new functionality of a new search strategy, and in the meantime want to run the already written tests under both configurations. As we have multiple classes each with multiple tests I want to streamline this process as much as possible. Ideally it'd be great to do the setup in a #BeforeClass with a data provider so that all tests in the class are basically run twice under the different configurations, but doesn't look like this is possible.
Right now I have:
public class SearchTest1 {
#Test(dataProvider = "SearchType")
public void test1(SearchType searchType) {
setSearchType(searchType);
//Do the test1 logic
}
#Test(dataProvider = "SearchType")
public void test2(SearchType searchType) {
setSearchType(searchType);
//Do the test2 logic
}
#DataProvider(name = "SearchType")
public Object[][] createData() {
return new Object[][]{
new Object[] {SearchType.scheme1, SearchType.scheme2}
}
}
}
Is there a better way to do this?
If you want to avoid having to annotate each and every method with the data provider, you can use a Factory instead.
public class SearchTest1 {
private final SearchType searchType;
public SearchTest1( SearchType searchType ) {
this.searchType = searchType;
}
#Test
public void test2() {
//Do the test2 logic
}
...
}
And your factory class will be:
public class SearchTestFactory {
#Factory
public Object [] createInstances() {
return new Object[] { new SeartchTest1( SearchType.ONE ), new SearchTest1( SearchType.TWO ) };
}
}
See more on this here.
Then you can either have one factory that enumerates every test class or a separate factory for each, the first one is obviously less flexible, the second one means slightly more code.
You can use parameters in #BeforeClass. Just use (with some cleanup)
context.getCurrentXmlTest().getParameters()
#SuppressWarnings("deprecation")
#BeforeClass
public void setUp(ITestContext context) {
System.out.println(context.getCurrentXmlTest().getAllParameters());
}

Passing JUnit data between tests

I just discovered when creating some CRUD tests that you can't set data in one test and have it read in another test (data is set back to its initialization between each test).
All I'm trying to do is (C)reate an object with one test, and (R)ead it with the next. Does JUnit have a way to do this, or is it ideologically coded such that tests are not allowed to depend on each other?
Well, for unit tests your aim should be to test the smallest isolated piece of code, usually method by method.
So testCreate() is a test case and testRead() is another. However, there is nothing that stops you from creating a testCreateAndRead() to test the two functions together. But then if the test fails, which code unit does the test fail at? You don't know. Those kind of tests are more like integration test, which should be treated differently.
If you really want to do it, you can create a static class variable to store the object created by testCreate(), then use it in testRead().
As I have no idea what version of Junit you talking about, I just pick up the ancient one Junit 3.8:
Utterly ugly but works:
public class Test extends TestCase{
static String stuff;
public void testCreate(){
stuff = "abc";
}
public void testRead(){
assertEquals(stuff, "abc");
}
}
JUnit promotes independent tests. One option would be to put the two logical tests into one #Test method.
TestNG was partly created to allow these kinds of dependencies among tests. It enforces local declarations of test dependencies -- it runs tests in a valid order, and does not run tests that depend on a failed test. See http://testng.org/doc/documentation-main.html#dependent-methods for examples.
JUnit is independent test. But, If you have no ways, you can use "static" instance to store it.
static String storage;
#Test
public void method1() {
storage = "Hello"
}
#Test
public void method2() {
Assert.assertThat(something, is(storage));
}
How much processing time do these tests take? If not a lot, then why sweat it. Sure you will create some object unnecessarily, but how much does this cost you?
#Test
void testCreateObject() {
Object obj = unit.createObject();
}
#Test
void testReadObject() {
Object obj = null;
try {
obj = unit.createObject(); // this duplicates tests aleady done
} catch (Exception cause) {
assumeNoException(cause);
}
unit.readObject(obj);
}
in this basic example, the variable is changed in the test A, and can be used in the test B
public class BasicTest extends ActivityInstrumentationTestCase2 {
public BasicTest() throws ClassNotFoundException {
super(TARGET_PACKAGE_ID, launcherActivityClass);
}
public static class MyClass {
public static String myvar = null;
public void set(String s) {
myvar = s;
}
public String get() {
return myvar;
}
}
private MyClass sharedVar;
#Override
protected void setUp() throws Exception {
sharedVar = new MyClass();
}
public void test_A() {
Log.d(S,"run A");
sharedVar.set("blah");
}
public void test_B() {
Log.d(S,"run B");
Log.i(S,"sharedVar is: " + sharedVar.get());
}
}
output result is:
run A
run B
sharedVar is: blah

Specifying an order to junit 4 tests at the Method level (not class level)

I know this is bad practice, but it needs to be done, or I'll need to switch to testng. Is there a way, similar to JUnit 3's testSuite, to specify the order of the tests to be run in a class?
If you're sure you really want to do this: There may be a better way, but this is all I could come up with...
JUnit4 has an annotation: #RunWith which lets you override the default Runner for your tests.
In your case you would want to create a special subclass of BlockJunit4ClassRunner, and override computeTestMethods() to return tests in the order you want them executed. For example, let's say I want to execute my tests in reverse alphabetical order:
public class OrderedRunner extends BlockJUnit4ClassRunner {
public OrderedRunner(Class klass) throws InitializationError {
super(klass);
}
#Override
protected List computeTestMethods() {
List list = super.computeTestMethods();
List copy = new ArrayList(list);
Collections.sort(copy, new Comparator() {
public int compare(FrameworkMethod o1, FrameworkMethod o2) {
return o2.getName().compareTo(o1.getName());
}
});
return copy;
}
}
#RunWith(OrderedRunner.class)
public class OrderOfTest {
#Test public void testA() { System.out.println("A"); }
#Test public void testC() { System.out.println("C"); }
#Test public void testB() { System.out.println("B"); }
}
Running this test produces:
C
B
A
For your specific case, you would want a comparator that would sort the tests by name in the order you want them executed. (I would suggest defining the comparator using something like Google Guava's class Ordering.explicit("methodName1","methodName2").onResultOf(...); where onResultOf is provided a function that converts FrameworkMethod to its name... though obviously you are free to implement that any way you want.
I can see several reasons for doing this, especially when using JUnit to run functional tests or test persistent objects. For example, consider an object Article which is persisted to some kind of persistent storage. If I would like to test the insert, update and delete functionality on the Article object following the unit test principle "all tests should be reorderable and test only a specific part of the functionality", I would have three tests:
testInsertArticle()
testUpdateArticle()
testDeleteArticle()
However, to be able to test the update functionality, I would first need to insert the article. To test the delete functionality, I would also need to insert an article. So, in practice, the insert functionality is already tested both in testUpdateArticle() and testDeleteArticle(). It is then tempting to just create a test method testArticleFunctionality() which does it all, but methods like that will eventually get huge (and they won't just test part of the functionality of the Article object).
The same goes for running functional tests against for example a restful API. JUnit is great also for these cases if it wasn't for the undeterministic ordering of tests.
That said, I extended Michael D's OrderedRunner to use annotations to determine order of tests, just thought I should share. It can be extended further, for example by specifying exactly which tests each test depends on, but this is what I'm using for now.
This is how it is used. It avoids the need for naming tests like AA_testInsert(), AB_testUpdate(), AC_testDelete(), ..., ZC_testFilter(), etc.
#RunWith(OrderedRunner.class)
public class SomethingTest {
#Test
#Order(order=2)
public void testUpdateArticle() {
// test update
}
#Test
#Order(order=1)
public void testInsertArticle() {
// test insert
}
#Test
#Order(order=3)
public void testDeleteArticle() {
// test delete
}
}
No matter how these tests are placed in the file, they will always be run as order=1 first, order=2 second and last order=3, no matter if you run them from inside Eclipse, using Ant, or any other way.
Implementation follows. First, the annotation Order.
#Retention(RetentionPolicy.RUNTIME)
public #interface Order {
public int order();
}
Then, the modified OrderedRunner.
public class OrderedRunner extends BlockJUnit4ClassRunner {
public OrderedRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected List<FrameworkMethod> computeTestMethods() {
List<FrameworkMethod> copy = new ArrayList<>(super.computeTestMethods());
Collections.sort(list, new Comparator<FrameworkMethod>() {
#Override
public int compare(FrameworkMethod f1, FrameworkMethod f2) {
Order o1 = f1.getAnnotation(Order.class);
Order o2 = f2.getAnnotation(Order.class);
if(o1==null && o2 == null) return 0;
if (o1 == null) return 1;
if (o2 == null) return -1;
return o1.order() - o2.order();
}
});
return list;
}
}
From JUnit version 4.11 onwards, it is possible to influence the order of test execution by annotating your class with #FixMethodOrder and specifying any of the available MethodSorters. See this link for more details.
Using junit 4.11 the new annotation #FixMethodOrder allows to set a specific order:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
If you want to run junit tests in order "just as they present in your source code",
and don't want to modify your tests code,
see my note about this here:
How to run junit tests in order as they present in your source code
But it is really not a good idea, tests must be independent.
Joscarsson and Michael D code in my github repo. I hope they don't mind. I also provide ordered version for Parameterized class. It's already to use as maven dependency
<repositories>
<repository>
<id>git-xxx</id>
<url>https://github.com/crsici/OrderedRunnerJunit4.11/raw/master/</url>
</repository>
</repositories>
<dependency>
<groupId>com.sici.org.junit</groupId>
<artifactId>ordered-runner</artifactId>
<version>0.0.1-RELEASE</version>
</dependency>

Categories