Workaround to support org.junit.runners.Parameterized in Gradle - java

Gradle is unable to run JUnit tests annotated with:
import org.junit.runners.Parameterized;
#RunWith(value = Paremetrized.class)
public class UnitTest {
// ...
}
There is an official issue for this problem from June 2014 yet unsolved.
Are there any workarounds for enabling those tests (in Gradle 2.4)?

An alternative for JUnit's Parameterized is the open source third-party library junit-dataprovider. It is supported by Gradle (tested with 2.4).
The usage is similar:
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
#RunWith(DataProviderRunner.class)
public class DataProviderTest {
#DataProvider
public static Object[][] dataProviderAdd() {
// #formatter:off
return new Object[][] {
{ 0, 0, 0 },
{ 1, 1, 2 },
/* ... */
};
// #formatter:on
}
#Test
#UseDataProvider("dataProviderAdd")
public void testAdd(int a, int b, int expected) {
// Given:
// When:
int result = a + b;
// Then:
assertEquals(expected, result);
}
}
The dependency line for Gradle:
testCompile 'com.tngtech.java:junit-dataprovider:1.9.3'

Related

Mock whenever new instance created without PowerMockito JUnit5

JUnit5 does not support PowerMockRunner hence the following code will not work whenever you migrate from JUnit4 to JUnit5.
Eg.
Code you trying to inject mock
import javax.naming.InvalidNameException;
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.publish();
}
public void publish() {
try {
Sample s = new Sample();
s.invoke("Hello");
} catch (InvalidNameException e) {
throw new ServiceFailureException(e.getMessage());
}
}
}
Here you are trying to test publish method where you mock the Sample instance to respond with different responses.
In JUnit4 you could have use PowerMockito to achieve that.
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.naming.InvalidNameException;
#RunWith(PowerMockRunner.class)
#PrepareForTest({Main.class})
public class MainTest {
#Test
public void testPublishSuccess() {
Main m = new Main();
Assert.assertEquals("Expected result not found", "success", m.publish());
}
#Test
public void testPublishFailure() throws Exception{
Sample sample = new Sample();
PowerMockito.when(sample.invoke(Mockito.anyString())).thenReturn("failure");
PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);
Main m = new Main();
Assert.assertEquals("Expected result not found", "failure", m.publish());
}
#Test(expected = ServiceFailureException.class)
public void testPublishException() throws Exception{
Sample sample = new Sample();
PowerMockito.when(sample.invoke(Mockito.anyString())).thenThrow(new InvalidNameException("Invalid name provided"));
PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);
Main m = new Main();
m.publish();
}
}
With the introduction of JUnit5, the test cases are failing at mock creating new instances because PowerMockRunner does not support JUnit5.
What is the alternate for using PowerMockito with JUnit5.
As PowerMockito does not support JUnit5, we can use Mockito inline. Here is the code which replace the PowerMockito.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import javax.naming.InvalidNameException;
public class MainTestJunit5 {
#Test
public void testPublishSuccess() {
Main m = new Main();
Assertions.assertEquals("success", m.publish(), "Expected result not found");
}
#Test
public void testPublishFailure() throws Exception{
try (MockedConstruction<Sample> mockedConstruction = Mockito.mockConstruction(Sample.class, (sampleMock, context) -> {
Mockito.when(sampleMock.invoke(Mockito.anyString())).thenReturn("failure");
})) {
Sample sample = new Sample();
PowerMockito.when(sample.invoke(Mockito.anyString())).thenReturn("failure");
PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);
Main m = new Main();
Assertions.assertEquals("Expected result not found", "failure", m.publish());
}
}
#Test
public void testPublishException() throws Exception{
try (MockedConstruction<Sample> mockedConstruction = Mockito.mockConstruction(Sample.class, (sampleMock, context) -> {
Mockito.when(sampleMock.invoke(Mockito.anyString())).thenThrow(new InvalidNameException("Invalid name found"));
})){
Main m = new Main();
boolean error = false;
try {
m.publish();
} catch (ServiceFailureException e) {
error = true;
}
Assertions.assertTrue(error, "Exception throwing expected");
}
}
}
Couple of things you need to pay attention
Setting up mockito-inline need additional dependency and an additional configuration.
Extra test runners (PowerMockRunner) and preparation for testing is not needed.
MockedConstruction is scoped, so you have to put all the mocking and processing done within that code block.
JUnit5 messages are the final method argument.
Mockito documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#49

running junit form command line: initializationError(SLLTest): No runnable methods

I am trying to execute Junit test using Powershell script. But I keep getting initializationError(SLLTest): No runnable methods
The same test cases run fine from eclipse. I am also overriding the classpath to use the same jars eclipse uses during both compilation and execution.
// TestRunner
import java.io.PrintStream;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class TestRunner {
public static void main(String[] args) {
PrintStream original = System.out;
Result result = JUnitCore.runClasses(TestSuite.class);
System.setOut(original);
for(Failure failure : result.getFailures())
System.out.println(failure);
if(result.wasSuccessful())
System.out.println("Success");
}
}
// one of the test classes
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.Test;
public class StackQTest{
StackQ s = new StackQ();
#Test
public void pushPopTest() {
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
assertEquals(5, s.pop());
assertEquals(4, s.pop());
assertEquals(3, s.pop());
assertEquals(2, s.pop());
assertEquals(1, s.pop());
}
}
// test suite class
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith (Suite.class)
#SuiteClasses ({SLLTest.class, DLLTest.class, RecursionTest.class,
QueueSTest.class, StackQTest.class})
public class TestSuite {
}
I am expecting "Success" as an output put I always get:
initializationError(SLLTest): No runnable methods
initializationError(DLLTest): No runnable methods
initializationError(RecursionTest): No runnable methods
initializationError(QueueSTest): No runnable methods
initializationError(StackQTest): No runnable methods

mockito UnfinishedStubbingException missing thenReturn or you are trying to stub a final method

I am trying to run the below unit test - TestDummy using TestNG, Mockito on Java7
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import junit.framework.Assert;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.annotations.Test;
#PrepareForTest({TestA.class, TestB.class, Result.class, C.class})
public class TestDummy {
#Test
public void testIt() throws Exception {
mockStatic(TestB.class);
Result r = mock(Result.class);
r.res = 2;
TestB tB = mock(TestB.class);
doReturn(tB).when(TestB.class, "get");
when(tB.doSome(any(C.class))).thenReturn(r);
Result rA = TestA.run();
Assert.assertEquals(2, rA.res);
}
}
Below is the source code I am trying to run the above unit test for -
class TestA {
public static Result run() {
TestB tB=TestB.get();
return tB.doSome(new C());
}
}
class Result {
int res;
}
class TestB {
static final TestB INS = new TestB();
public static TestB get() {
return INS;
}
public Result doSome(C c) {
Result r = new Result();
r.res=1;
return r;
}
}
class C {
}
but fails with the below error -
Running TestDummy
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.268 sec <<< FAILURE! - in TestDummy
testIt(TestDummy) Time elapsed: 0.527 sec <<< FAILURE!
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:36)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
at TestDummy.testIt(TestDummy.java:25)
Looks to be a trivial issue but stuck up here for a while. Would appreciate any inputs to resolve this without modifying the source code (modifying the unit test - TestDummy should be fine). I saw many posts regarding similar/same issues, however those suggestions doesn't seem to work here.
With Junit you use #RunWith but with TestNG you would need to specify this in your test case:
#ObjectFactory public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
Remember to add this dependency in your pom:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.3</version>
<scope>test</scope>
</dependency>
This question is tagged with junit4 but the supplied code (which is a very useful MCVE, thanks :) suggests that you are using testng, TestDummy includes this import
org.testng.annotations.Test
So, I'm not sure which you are using.
Anyway, your code looks solid, I ran it successfully by making one simple change; adding #RunWith(PowerMockRunner.class) to TestDummy.
This was verified using the following:
JUnit 4.12
Powermock 1.7
Mockito 2.7.19.

using gradle, error: cannot find symbol #Test

I am trying to build the tests using gradle in the project.
On building the tests, I am getting error ->
:compileTestJava/home/vibhcool/Documents/github/loklak_server/test/org/loklak/harvester/TwitterScraperTest.java:28: error: cannot find symbol
#TEST
^
symbol: class TEST
location: class TwitterScraperTest
1 error
FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileTestJava'.
The file in which I am getting error ->
package org.loklak.harvester;
import java.io.File;
import java.io.IOException;
import org.junit.After;
import org.junit.Before;
import org.loklak.harvester.TwitterScraper;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TwitterScraperTest {
#TEST
public void test_prepareSearchURL() {
String url;
String[] query = {"q1", "q2", "q3", };
String[] out_url = {"url1", "url2", "url3"};
for (int i = 0; i < query.length; i++) {
url = TwitterScraper.prepareSearchURL(query[i]);
assertEquals(url, out_url[i]);
}
}
}
When I comment #TEST in the file, gradle successfully builds the tests.
I have googled a lot but, not able to get the error.
I am using junit 4.10
It should be :
#Test
public void test_prepareSearchURL() {
...
}
and not
#TEST
public void test_prepareSearchURL() {
..
}
You can take a look on how to get started with Junit here.

Can't verify mock method call from RxJava Subscriber

I'm trying to unit test presenter in my Android app. Method I'm trying to test looks like this:
#Override
public boolean loadNextPage() {
if (!mIsLoading) {
mIsLoading = true;
if (mViewReference.get() != null) {
mViewReference.get().showProgress();
}
mService.search(mSearchQuery, ++mCurrentPage)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(itemsPage -> {
mIsLoading = false;
mTotalPages = itemsPage.getPagination().getTotalPages();
if (mViewReference.get() != null) {
mViewReference.get().showMovies(itemsPage.getItems());
}
},
error -> {
mIsLoading = false;
Log.d(LOG_TAG, error.toString());
});
}
return mTotalPages == 0 || mCurrentPage < mTotalPages;
}
mService is Retrofit interface and mService.search() method returns RxJava's Observable<SearchResults>. My unit test code looks like this:
package mobi.zona.presenters;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import com.example.api.Service;
import com.example.model.Movie;
import com.example.model.SearchResults;
import com.example.views.MoviesListView;
import rx.Observable;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class SearchPresenterTest {
#Mock
Service mService;
#Mock
MoviesListView mMoviesListView;
#Test
public void testLoadNextPage() throws Exception {
String searchQuery = "the hunger games";
SearchResults searchResults = new SearchResults();
List<Movie> movies = new ArrayList<>();
searchResults.setItems(movies);
when(mService.search(searchQuery, 1)).thenReturn(Observable.just(new SearchResults()));
MoviesListPresenter presenter = new SearchPresenter(mZonaService, mMoviesListView, searchQuery);
presenter.loadNextPage();
verify(mService, times(1)).search(searchQuery, 1);
verify(mMoviesListView, times(1)).showProgress();
verify(mMoviesListView, times(1)).showMovies(movies);
}
}
The problem is the third verify(mMoviesListView, times(1)).showMovies(movies); line - it allways fails. Whem I'm trying to debug this test I see that control flow never goes into .subscribe(itemPage - {.... I think that it's something related to the fact that I'm subscribing on Schedulers.io() thread, but have no idea on how to fix this. Any ideas?
EDIT 1:
Changed the presenter to take Scheduler's as constructor parameters. Changed test to look like this:
#Test
public void testLoadNextPage() throws Exception {
String searchQuery = "the hunger games";
SearchResults searchResults = new SearchResults();
List<Movie> movies = new ArrayList<>();
searchResults.setItems(movies);
when(mZonaService.search(searchQuery, 1)).thenReturn(Observable.just(new SearchResults()));
MoviesListPresenter presenter = new SearchPresenter(mZonaService, mMoviesListView, searchQuery,
Schedulers.test(), Schedulers.test());
presenter.loadNextPage();
verify(mZonaService, times(1)).search(searchQuery, 1);
verify(mMoviesListView, times(1)).showProgress();
verify(mMoviesListView, times(1)).showMovies(movies);
}
Still getting this test failure message:
Wanted but not invoked:
mMoviesListView.showMovies([]);
-> at com.example.presenters.SearchPresenterTest.testLoadNextPage(SearchPresenterTest.java:46)
However, there were other interactions with this mock:
mMoviesListView.showProgress();
-> at com.example.presenters.SearchPresenter.loadNextPage(SearchPresenter.java:41)
In my apps interactors/use-cases/model (mService in your case) is responsible for specifying Scheduler for the operation (since it knows better what kind of operation it does).
So, move your subscribeOn to mService. After that your mock will work fine.
Going deeper, if now you'll want to test mService I would recommend you to make it "dependent" on Scheduler. In other words - add Sheduler as a constructor parameter.
public class MyService {
private final Scheduler taskScheduler;
public MyService(Scheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
// ...
public Observable<Something> query() {
return someObservable.subscribeOn(taskScheduler);
}
}
Then, in tests you can use Schedulers.immediate() and for actual app Schedulers.io() (or whatever you like, really).

Categories

Resources