TestNG dataproviders with a #BeforeClass - java

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());
}

Related

Is there a way to know inside a #MethodSource for which test method it's providing data?

In my TestClass I have a lot of different test methods that all have to run with the same data and therefore have the same #MethodSource:
public class TestClass {
private class TestData { /* some fields */ }
private List<TestData> testDataTemplates = asList(
new TestData(...),
/* some more elements */
);
static private Stream<Arguments> testDataProvider {
List<TestData> testData = new ArrayList<>();
// Here we do some nested .forEach iterating over the testDataTemplates
return testData.stream();
}
#ParametrizedTest
#MethodSource("testDataProvider")
public void testMethod1(...) { }
// some more test methods
#ParametrizedTest
#MethodSource("testDataProvider")
public void testMethodN(...) { }
}
For testMethodN it is necessary to have the data a tiny bit different than for the other methods. My idea was to detect inside testDataProvider for which method it is currently generating data and adapt the output accordingly.
Is there a way to do so?
If not, what it the cleanest way to achieve what I need to, underlining again, that the output of testDataProvider for testMethodN is really really similar to the output for the other test methods?
One could solve this using a new #MethodSource:
static private Stream<Arguments> filteredTestDataProvider() {
List<Arguments> testCases = new ArrayList<>();
testDataProvider().forEach(args -> {
// decide whether and how the current args are used
});
return testCases.stream();
}
And, of course, the #MethodSource("filteredTestDataProvider") of testMethodN should be adapted accordingly.

Spring boot Unit test about best practics and currectli writing tests

I want start write unit test in my project. I tried make this many times. And he always quit, because he could not understand the meaning. because I can not find and form knowledge into a single whole. I read many articles, saw many examples, and they are all different. As a result, I understand why I need write tests, I understand how to write them, but I do not understand how correctly. And I do not understand how to write them so that they are useful. I have some questions:
For example I have service:
#Service
public class HumanServiceImpl implements HumanService {
private final HumanRepository humanRepository;
#Autowired
public HumanServiceImpl(HumanRepository humanRepository) {
this.humanRepository = humanRepository;
}
#Override
public Human getOneHumanById(Long id) {
return humanRepository.getOne(id);
}
#Override
public Human getOneHumanByName(String firstName) {
return humanRepository.findOneByFirstName(firstName);
}
#Override
public Human getOneHumanRandom() {
Human human = new Human();
human.setId(Long.parseLong(String.valueOf(new Random(100))));
human.setFirstName("firstName"+ System.currentTimeMillis());
human.setLastName("LastName"+ System.currentTimeMillis());
human.setAge(12);//any logic for create Human
return human;
}
}
And I tried write Unit test for this service:
#RunWith(SpringRunner.class)
public class HumanServiceImplTest {
#MockBean(name="mokHumanRepository")
private HumanRepository humanRepository;
#MockBean(name = "mockHumanService")
private HumanService humanService;
#Before
public void setup() {
Human human = new Human();
human.setId(1L);
human.setFirstName("Bill");
human.setLastName("Gates");
human.setAge(50);
when(humanRepository.getOne(1L)).thenReturn(human);
when(humanRepository.findOneByFirstName("Bill")).thenReturn(human);
}
#Test
public void getOneHumanById() {
Human found = humanService.getOneHumanById(1L);
assertThat(found.getFirstName()).isEqualTo("Bill");
}
#Test
public void getOneHumanByName() {
Human found = humanService.getOneHumanByName("Bill");
assertThat(found.getFirstName()).isEqualTo("Bill");
}
#Test
public void getOneHumanRandom() {
//???
}
}
I have questions:
1. Where should I fill the objects? I saw different implementations
in #Before like in my example, in #Test, mix implementations - when Human create in #Before and expression
when(humanRepository.getOne(1L)).thenReturn(human);
in #Test method
private Human human;
#Before
public void setup() {
human = new Human();
...
}
#Test
public void getOneHumanById() {
when(humanRepository.getOne(1L)).thenReturn(human);
Human found = humanService.getOneHumanById(1L);
assertThat(found.getFirstName()).isEqualTo("Bill");
}
2. How can I test getOneHumanRandom() method?
Service not use repository when call this method. I can make this method mock, but what will it give?
when(humanService.getOneHumanRandom()).thenReturn(human);
...
#Test
public void getOneHumanRandom() {
Human found = humanService.getOneHumanRandom();
assertThat(found.getFirstName()).isEqualTo("Bill");
}
I just copy the logic from the service in the test class. What is the point of such testing and is it necessary?
1. Where should I fill the objects? I saw different implementations
I would use #Before for any common setup between all / most tests. Any setup that is specific to a certain test should be go into that test method. If there is a common setup between some, but not all, of your tests you can write private setup method(s).
Remember to keep your tests / code DRY (dont repeat yourself!). Tests have a maintenance factor and keeping common code together with help alleviate some headaches in the future.
2. How can I test getOneHumanRandom() method?
You should create a Human toString() method. This method should concat all the properties on your Human object. You can call getOneHumanRandom() twice and assert that they are not equal.
#Test
public void getOneHumanRandomTest()
{
// SETUP / TEST
Human one = service.getOneHumanRandom();
Human two = service.getOneHumanRandom();
// VERIFY / ASSERT
assertNotEquals("these two objects should not be equal", one.toString(), two.toString())
}
Hope this helps!

Customizing which tests to run with JUnit #Parameters?

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

How can I test if this object returns the correct String?

I have a Thing class that holds various Strings and a Collection of Stuff.
I have to test whether the Message class can correctly return item as "found" in a MessageTest class.
What is the most elegant/efficient way of testing this?
What kind of fake object should I create, and how do I test with/against it?
public class Thing
{
public String a;
public String b;
public String c;
public String d;
public String e;
public Collection<Stuff> collection;
}
public class Message
{
private String item;
public Message(Thing thing)
{
for (Stuff stuff : thing.collection)
{
if (stuff.getItem().equals("key"))
{
item = "found";
}
}
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append(a);
builder.append(b);
builder.append(c);
builder.append(d);
builder.append(e);
builder.append(item);
return builder.toString();
}
}
The idea of JUnit is to do unit testing. I think you should test a specific method that you know what it should do instead of "faking" anything (I understand mocking for faking), for example:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class PayrollTesCase {
#Test
public void testCalculate() {
Message m = new Message(new Thing("a", "b", "c", "d", "e"));
assertEquals("abcde", m.toString());
}
}
So, if in the future you change your Message.toString() implementation, you introduced a bug and it returns "cde" then your specific test case will fail. This is the idea behind unit testing.
I like this definition:
Unit Testing is a level of the software testing process where
individual units/components of a software/system are tested. The
purpose is to validate that each unit of the software performs as
designed.
In JUnit 4.x all the methods are annotated. So, the flow of control in JUnit methods can be described as below:
#BeforeClass -> #Before -> #Test -> #After -> #AfterClass
By the way, you have different degrees of testing, Unit Testing is the "smallest". I'm not sure what you need but maybe you want to do an Integration Test.

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

Categories