Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Since multiple @RunWith impossible, a static way to initialize the Runner is needed #79

Closed
sxilderik opened this issue May 4, 2016 · 21 comments
Assignees

Comments

@sxilderik
Copy link

sxilderik commented May 4, 2016

Hello

I'm using @RunWith(Arquillian.class) and I'd like to @DataProvide my tests there too.

Since there is no way to say @RunWith twice, how can I use @dataProvider in my Arquillian test class ?

Is there a way to statically initialize or do whatever mojo is needed to mimic the @RunWith(DataProviderRunner.class) ?

@before
public void init() {
DataProviderRunner.doTheMagic().
}

@sxilderik sxilderik changed the title Multiple @RunWith impossible, needs a static initializer Since multiple @RunWith impossible, a static initializer is needed May 4, 2016
@sxilderik sxilderik changed the title Since multiple @RunWith impossible, a static initializer is needed Since multiple @RunWith impossible, a static way to initialize the Runner is needed May 4, 2016
@aaschmid
Copy link
Member

aaschmid commented May 4, 2016

Hi @sxilderik, in the moment I have no idea how this should work as JUnit is very inflexible at this point. But maybe you can do the same as we did with @DataProvider and some dependency injection frameworks. The documentation how this works can be found here:

https://github.com/TNG/junit-dataprovider/wiki/Tips-and-Tricks

Would be great if you could test that out and if you like also add a documentation for it. If you encounter any problem, don't hesitate to ask :-)

Cheers,
Andreas

@aaschmid aaschmid self-assigned this May 4, 2016
@Vivek-Malhotra
Copy link

Vivek-Malhotra commented Jul 28, 2016

Hi Everyone,
I encountered similar issue as mentioned in this thread. I am new to Spring and Junit and if anybody can suggest any pointer to resolve it would be great.

I have a JUNIT Test “MyTest” as below which uses @RunWith and SpringJUnit4ClassRunner as below:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(TestConfiguration.class)
public class LarsStartCCTest extends LarsBaseTest {

@Before
public void before() {

    wireMockRule.stubFor(get(urlEqualTo("/lars/lars/invoice/201627JP00006087"))
            .willReturn(aResponse().withHeader("Content-Type", "text/xml").withBodyFile("K000006087.xml")));

    wireMockRule.stubFor(get(urlEqualTo("/lars/lars/invoice/201627JP00006088"))
            .willReturn(aResponse().withHeader("Content-Type", "text/xml").withBodyFile("K000006088.xml")));

    List<InvoiceData> invoices = new ArrayList<>();
    invoices.add(new InvoiceData("201627JP00006087"));
    invoices.add(new InvoiceData("201627JP00006088"));

    int updatedRows = dataCook.cookTestData(invoices);
    LOGGER.info("Data Cook Updated " + updatedRows + " Rows for Invoice Data");
    setXXSource(XXSource.STARTCC);
}

@After
public void tearDown() throws Exception {
    int deletedRows[] = dataCook.cleanTestData();
    LOGGER.info("Data Cook Deleted " + deletedRows.length + " Rows");
}

@test
@UseDataProvider(value = "dataProviderMethod", location = JunitDataProvider.class)
public void testLarsTamara(String invoiceId1, String invoiceId2) throws Exception {
LOGGER.info("Start test");
LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);
File file = larsRemote.runLars();
readAndVerifyLarsFile(file);
}

}

The test was running fine but I had lots of hardcoded data (Invoices) in @before and hence I thought of using TestNG DataProvider to suppy data and while searching this came across this JUNIT Data Provider.

I downloaded the dependencies for JUNIT DataProvider and written a separate class JunitDataProvider as below:

@RunWith(DataProviderRunner.class)
public class JunitDataProvider {

private static final Logger LOGGER = LoggerFactory.getLogger(JunitDataProvider.class);

@DataProvider
public static Object[][] dataProviderMethod() {
    return new Object[][]{
            {"201628JP00006097", "201628JP00006098"},
    };
}

@Test
@UseDataProvider("dataProviderMethod")
public void testParameterMethod(String invoiceId1, String invoiceId2) {
    LOGGER.info("Start test");
    LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);

}

}

Now the issue is If I run my test with @RunWith(SpringJUnit4ClassRunner.class) I get below exception
java.lang.Exception: Method testLarsTamara should have no parameters

If I run my test with @RunWith(DataProviderRunner.class) it gives

java.lang.NullPointerException in @before Method, below Line.

int updatedRows = dataCook.cookTestData(invoices);
LOGGER.info("Data Cook Updated " + updatedRows + " Rows for Invoice Data");

@aaschmid
Copy link
Member

aaschmid commented Jul 28, 2016

Hi @Vivek-Malhotra,

as already mentioned before, please see

https://github.com/TNG/junit-dataprovider/wiki/Tips-and-Tricks#dataprovider-for-spring-integration-testing

where a detailed guide is provided for using JUnit dataprovider (= DataProviderRunner) and Spring test runner (= SpringJUnit4ClassRunner). Unfortunately this requires some manual overriding of code. This is caused by JUnit as it is very inflexible according to extensions.

Does this help?

Cheers,
Andreas

P.S.: As JUnit Lambda (= JUnit 5) is a lot more flexible we have to wait for this to get it run using multiple extensions...

Am 28. Juli 2016 16:58:02 MESZ, schrieb Vivek-Malhotra notifications@github.com:

Hi Everyone,
I encountered similar issue as mentioned in this thread. I am new to
Spring and Junit and if anybody can suggest any pointer to resolve it
would be great.

I have a JUNIT Test “MyTest” as below which uses @RunWith and
SpringJUnit4ClassRunner as below:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(TestConfiguration.class)
public class LarsStartCCTest extends LarsBaseTest {

@before
public void before() {

  wireMockRule.stubFor(get(urlEqualTo("/lars/lars/invoice/201627JP00006087"))

.willReturn(aResponse().withHeader("Content-Type",
"text/xml").withBodyFile("K000006087.xml")));

wireMockRule.stubFor(get(urlEqualTo("/lars/lars/invoice/201627JP00006088"))
.willReturn(aResponse().withHeader("Content-Type",
"text/xml").withBodyFile("K000006088.xml")));

   List<InvoiceData> invoices = new ArrayList<>();
   invoices.add(new InvoiceData("201627JP00006087"));
   invoices.add(new InvoiceData("201627JP00006088"));

  int updatedRows = dataCook.cookTestData(invoices);

LOGGER.info("Data Cook Updated " + updatedRows + " Rows for Invoice
Data");
setXXSource(XXSource.STARTCC);
}

@after
public void tearDown() throws Exception {
int deletedRows[] = dataCook.cleanTestData();
LOGGER.info("Data Cook Deleted " + deletedRows.length + " Rows");
}

@test
public void testLarsStartCC() throws Exception {
File file= XXRemote.runXX();
readAndVerifyXXFile(file);
}

}

The test was running fine but I had lots of hardcoded data (Invoices)
in @before and hence I thought of using TestNG DataProvider to suppy
data and while searching this came across this JUNIT Data Provider.

I downloaded the dependencies for JUNIT DataProvider and written a
separate class JunitDataProvider as below:

@RunWith(DataProviderRunner.class)
public class JunitDataProvider {

private static final Logger LOGGER =
LoggerFactory.getLogger(JunitDataProvider.class);

@dataProvider
public static Object[][] dataProviderMethod() {
return new Object[][]{
{"201628JP00006097", "201628JP00006098"},
};
}

@test
@UseDataProvider("dataProviderMethod")
public void testParameterMethod(String invoiceId1, String invoiceId2) {
LOGGER.info("Start test");
LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);

}
}

Now the issue is If I run my test with
@RunWith(SpringJUnit4ClassRunner.class) I get below exception
java.lang.Exception: Method testLarsTamara should have no parameters

If I run my test with @RunWith(DataProviderRunner.class) it gives

java.lang.NullPointerException in @before Method, below Line.

int updatedRows = dataCook.cookTestData(invoices);
LOGGER.info("Data Cook Updated " + updatedRows + " Rows for Invoice
Data");


You are receiving this because you were assigned.
Reply to this email directly or view it on GitHub:
#79 (comment)

Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail gesendet.

@Vivek-Malhotra
Copy link

Thanks @aaschmid for your reply. I looked at the solution. It looks like in my TestClass I can extend SpringJUnit4ClassRunner class as shown below.

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class DataProviderRunnerWithSpring extends SpringJUnit4ClassRunner {
/* ... */
}

However the issue is that my Test Class Already extends from some other class and hence I don't know how I can extend from SpringJUnit4ClassRunner as well.

public class LasXXXTest extends LasBaseTest {
@before
@after
@test
}

@aaschmid
Copy link
Member

Hi @Vivek-Malhotra,

you don't need to extend the test class but annotate it with @RunWith(DataProviderRunnerWithSpring.class) instead. Isn't this what you wanted?

Cheers,
Andreas

@Vivek-Malhotra
Copy link

Thanks @aaschmid
That is really cool. I hope it works, but still one doubt. If you can help on this, it will get me going. Few of my questions might be silly but I am new to this Spring world and trying to learn new things.

As you mentioned, I have downloaded DataProviderRunner.java and tried to do the below workarounds which you have mentioned. However in DataProviderRunner.java, I can't find any statement.evaluate() or any other functions you mentioned

https://github.com/TNG/junit-dataprovider/wiki/Tips-and-Tricks#dataprovider-for-spring-integration-testing

The body of this class is identical with DataProviderRunner.java but needs a small hack to work. Without any modification a NullPointerException is thrown in

The simplest solution is to comment out statement.evaluate();, which obviously breaks the @BeforeClass annotation. Alternatively, replacing the function above by the following two functions also fixes the issue without breaking @BeforeClass.

@Vivek-Malhotra
Copy link

Vivek-Malhotra commented Jul 29, 2016

Hi @aaschmid

Some progress made.

Now after creating a DataProviderRunner and Creating a dataProvider in JunitDataProvider.java I am getting below error:

java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]. Specify @BootstrapWith's 'value' attribute or make the default bootstrapper class available.

@RunWith(DataProviderRunnerWithSpring.class)
@SpringApplicationConfiguration(TestConfiguration.class)
public class LaxTest extends LaxBaseTest {

@test
@UseDataProvider(value = "testLaxTam", location = JunitDataProvider.class)
public void testLaxTam(String invoiceId1, String invoiceId2) throws Exception {
LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);
File file = laxRemote.runLax();
readAndVerifyLarxFile(file);
}

}

@Vivek-Malhotra
Copy link

Hello @aaschmid
Tried to do everything from Scratch. My Tests were running fine. Then after following steps below error is coming:

1, Created a JunitDataProvider class with test data
2. Created DataProviderRunnerWithSpring class which extends SpringJUnit4ClassRunner
3. Did the workarounds you mentioned
4. Changed test class method as below

@test
@UseDataProvider(value = "testDataForLaxTest", location = JunitDataProvider.class)
public void testLarx(String invoiceId1, String invoiceId2) throws Exception {
LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);
File file = larsRemote.runLax();
readAndVerifyLaxFile(file);
}

  1. Changed RunWith in Test class as below - @RunWith(DataProviderRunnerWithSpring.class)

java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]. Specify @BootstrapWith's 'value' attribute or make the default bootstrapper class available.

at org.springframework.test.context.BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.java:143)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:143)
at com.wirecard.qa.lars.config.DataProviderRunnerWithSpring.<init>(DataProviderRunnerWithSpring.java:65)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:98)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Caused by: java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotatedElementUtils.findAllMergedAnnotations(Ljava/lang/reflect/AnnotatedElement;Ljava/lang/Class;)Ljava/util/Set;
at org.springframework.test.context.BootstrapUtils.resolveExplicitTestContextBootstrapper(BootstrapUtils.java:150)
at org.springframework.test.context.BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.java:126)
... 23 more

Process finished with exit code -1

Do you know what could be the isssue here. I think something in POM is creating this issue.

@aaschmid
Copy link
Member

aaschmid commented Jul 29, 2016

Hi @Vivek-Malhotra,

sorry the tips and tricks page was outdated a bit as the adjustments where not necessary if you use v.1.10.4 or newer. I have updated the documentation and just added an example to the integration tests, see https://github.com/TNG/junit-dataprovider/tree/spring-acceptance-test/src/integTest/java/com/tngtech/test/java/junit/dataprovider/spring.

Does this help?

Cheers,
Andreas

P.S.: This does not use Spring Boot but should be also runnable within a Spring Boot application.

@aaschmid
Copy link
Member

Oh, haven't overseen your latest comment @Vivek-Malhotra. I guess you are correct, this is a problem in your POM i.e. it is caused by a dependency version conflict, e.g. some spring-boot version which does not match the corresponding spring-core library...
If you want me to help I require an reproducer or your POM ...

Cheers,
Andreas

@aaschmid
Copy link
Member

@sxilderik Are your problems solved using the tips and tricks page? Such that I can close this issue in the near future?

@Vivek-Malhotra
Copy link

Vivek-Malhotra commented Aug 1, 2016

Thanks @aaschmid

It works for me now. There were some issues with POM which I managed to rectify and it worked now.

I can access test data from Data Provider in my Test class like below:

Just one last question: Can we use this Dataprovider during test setup in @before ??

@RunWith(DataProviderRunnerWithSpring.class)
@SpringApplicationConfiguration(TestConfiguration.class)
public class LaxTest extends LaxBaseTest {
@test
@UseDataProvider(value = "testDataForLaxTest", location = JunitDataProvider.class)

public void testLax(String invoiceId1, String invoiceId2) throws Exception {
LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);
File file = larxRemote.runLax();
readAndVerifyLaxFile(file);
}
}

**@before
@UseDataProvider(value = "testDataForLarsTamaraTest", location = JunitDataProvider.class)
public void before(String invoiceId1, String invoiceId2) {

    LOGGER.info("Test data is: {}, {}", invoiceId1, invoiceId2);

}**

If I try to use it in @before class, I get error like below:
java.lang.Exception: Method before should have no parameters

Many Thanks once again.

@aaschmid
Copy link
Member

aaschmid commented Aug 1, 2016

Hi @Vivek-Malhotra,
you cannot use the DataProvider in the @Before. Can you tell me the use case as I am currently not seeing some because maybe this is a proper feature request? Maybe you can open a new ticket for it describing the use case to not cluttering this issue ...
Cheers,
Andreas

@Vivek-Malhotra
Copy link

Vivek-Malhotra commented Aug 2, 2016

Thanks @aaschmid
You can close this thread as the solution you provided is working fine now after the tweaks. Pretty cool.

Regarding the use case in @before I am not sure whether that is correct as I am pretty new to spring. What I though from my previous experience on other Test Frameworks, I used to do any prerequisites for a test in a setup script.

Similarly, there should be an option to use test data from test data provider in @before.

For e.g. I have a use case, where my Test Need some XML Invoices which are coming from a Mock. I am starting the Mock in @before and would like to pass the test data which my Mock needs in @before.

Then in @before I am hosting the mock with the XML invoices from Test Data Provider. Then I am adding some Test Data in some DB based on the Data from Test Data provider. All this is prerequisite for my test to run. Since it doesn't work in @before. I am simply doing in in @test at the moment and that's fine. However, it would have been nice to have similar feature in @before.

What are your views on this?

@aaschmid
Copy link
Member

aaschmid commented Aug 2, 2016

See #82 to follow up on this

@aaschmid
Copy link
Member

Since no more response on this, I will close the issue

@aaschmid
Copy link
Member

aaschmid commented Jan 2, 2018

Hi @alexandroid, thanks for the hint. I recently updated the referenced branch to the new master with containing subprojects now and overlooked that it was referenced in the "Tips and Tricks" page.

I fixed the links in the documentation.
The above link should now be https://github.com/TNG/junit-dataprovider/tree/spring-acceptance-test/junit4/src/integTest/java/com/tngtech/test/java/junit/dataprovider/spring.

If you have any further questions or issues, please don't hesitate to create an issue or add a comment here :-)

Cheers,
Andreas

@pedrocatre
Copy link

Instructions above did not work for me, they seem outdated or I did something wrong.
Maybe this helps someone, I followed the instructions here https://www.lenar.io/junit-dataprovider-with-spring-example/ they are clear and work.

@aaschmid
Copy link
Member

Thanks for this comment. Do you have an exception message or compile error for me? Which versions do you use?
(I also added the link to the corresponding wiki page.

@pedrocatre
Copy link

I think I used "junit-dataprovider v1.10.0" as mentioned and not all imports in https://github.com/TNG/junit-dataprovider/blob/master/junit4/src/main/java/com/tngtech/java/junit/dataprovider/DataProviderRunner.java got resolved. I quickly moved on to other instructions so maybe there was something I did not read. For example I just saw mentioned that I should have "cdi-unit v3.1.3" as a dependency and I did not have that dependency. Since the instructions on the link I posted work well I did not dig into the problems I was having. Version of junit-dataprovider used on the link is also more recent "1.13.1".
Off topic thank you for this project, it is very useful 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants