I'm facing an issue where ServiceLoader does not find one provided service.
I have tested with regular project and the following sources:
// test/Tester.java
package test;
public interface Tester {
}
// test/TesterImpl.java
package test;
public class TesterImpl implements Tester {
}
// test/Runner.java
package test;
import java.util.ServiceLoader;
public class Runner {
public static void main(String[] args) {
var loader = ServiceLoader.load(Tester.class);
for (var tester : loader) {
System.out.println(tester);
}
}
}
// module-info.java
import test.Tester;
import test.TesterImpl;
module module {
uses Tester;
provides Tester with TesterImpl;
}
The above prints something akin to test.TesterImpl#1fb3ebeb, proving that it works as wanted.
The same fails to work when I try to use ServiceLoader.load(...) inside an AbstractProcessor that's run through maven-compiler-plugin. The processor returns an empty iterator instead. What is required to make it behave the same way in the annotation processor as it does in the case above?
THe solution to this issue was to specify a class loader - it appears that the annotation processor used a different classloader than the classes I was trying to load the services from. Solution is the following:
ServiceLoader.load(MyService.class, MyAnnotationProcessor.class.getClassLoader())
Related
I'm using Guice for dependency injection and I'm a bit confused. There are two Named annotations in different packages:
com.google.inject.name.Named and javax.inject.Named (JSR 330?).
I'm eager to depend on javax.inject.*. Code sample:
import javax.inject.Inject;
import javax.inject.Named;
public class MyClass
{
#Inject
#Named("APrefix_CustomerTypeProvider")
private CustomerTypeProvider customerTypeProvider;
}
In my naming module I may have the following line:
bind(CustomerTypeProvider.class).annotatedWith(...).toProvider(CustomerTypeProviderProvider.class);
The question: I'm curious what should I put where the dots are? I would expect something like com.google.inject.name.Names.named("APrefix_CustomerTypeProvider") but this one returns com.google.inject.name.Named while I need the one in javax.inject.
CustomerTypeProviderProvider.class.getAnnotation(javax.inject.Named.class) also does not fit well because the CustomerTypeProviderProvider (ignore the stupid name, legacy issue) is not annotated.
As mentioned on the Guice wiki, both work the same. You shouldn't worry about that. It is even recommended to use javax.inject.* when available, just as you prefer too (bottom of the same page).
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.name.Names;
import javax.inject.Inject;
public class Main {
static class Holder {
#Inject #javax.inject.Named("foo")
String javaNamed;
#Inject #com.google.inject.name.Named("foo")
String guiceNamed;
}
public static void main(String[] args) {
Holder holder = Guice.createInjector(new AbstractModule(){
#Override
protected void configure() {
// Only one injection, using c.g.i.Names.named("").
bind(String.class).annotatedWith(Names.named("foo")).toInstance("foo");
}
}).getInstance(Holder.class);
System.out.printf("javax.inject: %s%n", holder.javaNamed);
System.out.printf("guice: %s%n", holder.guiceNamed);
}
}
Prints:
java.inject: foo
guice: foo
I wanted to implement a custom Application class Shadow, to override a getInstance() method in it. I am using Robolectric 3.0 and have created a MyRobolectricTestRunner class, overriding the createClassLoaderConfig() method like this:
public class MyRobolectricTestRunner extends RobolectricTestRunner {
public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
#Override
public InstrumentationConfiguration createClassLoaderConfig() {
InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder();
builder.addInstrumentedClass(App.class.getName());
return builder.build();
}
}
The ShadowApp class looks like this:
#Implements(App.class)
public class ShadowApp{
#RealObject private static App instance;
public static void setAppInstance(App app){
instance = app;
}
#Implementation
public static App getInstance(){
return instance;
}
}
And the test which uses the Runner is annotated like this:
#RunWith(MyRobolectricTestRunner.class)
#Config(manifest=Config.NONE, shadows = {ShadowApp.class}, constants = BuildConfig.class, sdk = 21)
public class SomeShadowTest {
Now the problem is that when I run the test manually (hitting "Run..." for this single test class only), it passes without a problem, but when I use the Gradle "testDebug" task, the test fails as if the Shadow class was not used at all :(
I have tried changing the Runner parent class to RobolectricGradleTestRunner, but ended up in a dead end when it forced me to make the ShadowApp class extend a ShadowApplication class, which has getInstance() method as well... :(
Any tips on how to solve this issue?
I suggest you do not create shadow for application but instead use TestApplication class which Robolectric uses as test variant of the application class.
For this you just need to create class which extends your application class and has name Test and is placed in the root of your project - package of class same as package name of project.
See example below:
Assume, you package name is com.example.robolectric
// src/main/java/com/example/robolectric
public class YourAplication extends Application {
...
}
// src/test/java/com/example/robolectric
/**
* Robolectric uses class with name Test<ApplicationClassName> as test variant of the application
* class. We use test application for API class injection so we need test version of this class.
*/
public class TestYourAplication extends YourAplication {
...
}
I write unit test and want to use JUnitParamsRunner and MockitoJUnitRunner for one test class.
Unfortunately, the following does not work:
#RunWith(MockitoJUnitRunner.class)
#RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
Is there a way to use both, Mockito and JUnitParams in one test class?
You cannot do this because according to spec you cannot put the same annotation twice on the same annotated element.
So, what is the solution? The solution is to put only one #RunWith() with runner you cannot stand without and replace other one with something else. In your case I guess you will remove MockitoJUnitRunner and do programatically what it does.
In fact the only thing it does it runs:
MockitoAnnotations.initMocks(test);
in the beginning of test case. So, the simplest solution is to put this code into setUp() method:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
I am not sure, but probably you should avoid multiple call of this method using flag:
private boolean mockInitialized = false;
#Before
public void setUp() {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
}
However better, reusable solution may be implemented with JUnt's rules.
public class MockitoRule extends TestWatcher {
private boolean mockInitialized = false;
#Override
protected void starting(Description d) {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
}
}
Now just add the following line to your test class:
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
and you can run this test case with any runner you want.
As of JUnit 4.7 and Mockito 1.10.17, this functionality is built in; there is an org.mockito.junit.MockitoRule class. You can simply import it and add the line
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
to your test class.
This solution works for every possible runner, not just this mockito example. For example; for Spring, just change the runner classes and add necessary annotations.
#RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
#Test
public void subRunner() throws Exception {
JUnitCore.runClasses(TestMockitoJUnitRunner.class);
}
#RunWith(MockitoJUnitRunner.class)
public static class TestMockitoJUnitRunner {
}
}
DatabaseModelTest will be run by JUnit. TestMockitoJUnitRunner depends on it (by logic) and it will be run inside of the main in a #Test method, during the call JUnitCore.runClasses(TestMockitoJUnitRunner.class). This method ensures the main runner is started correctly before the static class TestMockitoJUnitRunner sub-runner runs, effectively implementing multiple nested #RunWith annotations with dependent test classes.
Also on https://bekce.github.io/junit-multiple-runwith-dependent-tests
Since the release of PowerMock 1.6, you can do it as easily as
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
Explained here https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/
In my case I was trying to Mock some method in spring bean and
MockitoAnnotations.initMocks(test);
doesn't works. Instead you have to define that bean to constructed using mock method inside your xml file like following.
...
<bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
</bean>
...
and add that bean with autowired inside your test class like following.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="file:springconfig.xml")
public class TestClass {
...
#Autowired
private ClassWantedToBeMocked classWantedToBeMocked;
...
when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
...
}
check out this link https://bekce.github.io/junit-multiple-runwith-dependent-tests/
using this approach i combined a #RunWith(Parameterized.class) - outer runner - with #RunWith(MockitoJUnitRunner.class) - inner runner. The only tweak i had to add was to make my member variables in the outer class/runner static in order to make them accessible for the inner/nested runner/class. gook luck and enjoy.
I wanted to run SWTBotJunit4ClassRunner and org.junit.runners.Parameterized at the same time, I have parametric tests and I want to screenshots when the SWT test fails (the screenshot feature is provided by the SWTBotJunit4ClassRunner). #bekce's answer is great and first wanted go that route but it was either quirky passing through the arguments. Or doing the parametrized in the subclass and loosing the information what exact tests passed/failed and have only the last screenshot (as the screenshot names get the name from the test itself). So either way it was bit messy.
In my case the SWTBotJunit4ClassRunner is simple enough, so I cloned the source-code of the class, gave it my own name ParametrizedScreenshotRunner and where original was extending the TestRunner, my class is extending the Parameterized class so in essence I can use my own runner instead of the previous two. Boiled down my own runner extends on top of Parameterized runner while implementing the screenshot feature on top of it, now my test use this "hybrid" runner and all the tests work as expected straight away (no need to change anything inside the tests).
This is how it looks like (for sake of brevity I removed all the comments from the listing):
package mySwtTests;
import org.junit.runners.Parameterized;
import org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
public class ParametrizedScreenshotRunner extends TestRu Parameterized {
public ParametrizedScreenshotRunner(Class<?> klass) throws Throwable {
super(klass);
}
public void run(RunNotifier notifier) {
RunListener failureSpy = new ScreenshotCaptureListener();
notifier.removeListener(failureSpy); // remove existing listeners that could be added by suite or class runners
notifier.addListener(failureSpy);
try {
super.run(notifier);
} finally {
notifier.removeListener(failureSpy);
}
}
}
While there are no solution in JUnit 4 it is possible to register multiple extensions in JUnit 5:
#ExtendWith(MockitoExtension.class)
#ExtendWith(AnotherExtension.class)
public class MyTest {
// some tests
}
Note that JUnitParams framework is built into JUnit 5.
You can also try this:
#RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
// some tests
}
#RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
// some tests
}
I am trying to learn Guice for dependency Injection using Providers to create multiple instances of an object(Example from getting started guide on Guice website). how should I test this? Please advise.
The following is the module:
package testing;
import com.google.inject.AbstractModule;
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(BillingService.class).to(RealBillingService.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}
}
The following is the class under test:
package testing;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class RealBillingService implements BillingService {
private Provider<CreditCardProcessor> processorProvider;
private Provider<TransactionLog> transactionLogProvider;
#Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public void chargeOrder() {
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
processor.toString();
transactionLog.toString();
}
}
The following is the test class with main():
public class test {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
billingService.chargeOrder();
}
}
Upon running this, I am expecting the output from the following toString methods to show up but am seeing nothing:
processor.toString();
transactionLog.toString();
What am i missing here?
Please advise,
thanks!
This happens because you just call toString without putting the resulting string anywhere (eg the call to System.out.println)
However providers are not intended to be used like that. You should not call Provider.get yourself: instead require the result of the provider, register your provider and let Guice do its job (you can also annotate methods in your modules with #Provides instead of defining provider classes)
By default providers are called each time a new instance of a certain class is required. Instances are not recycled unless you explicitly request it via using scopes (like the builtin Singleton)
I write unit test and want to use JUnitParamsRunner and MockitoJUnitRunner for one test class.
Unfortunately, the following does not work:
#RunWith(MockitoJUnitRunner.class)
#RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
Is there a way to use both, Mockito and JUnitParams in one test class?
You cannot do this because according to spec you cannot put the same annotation twice on the same annotated element.
So, what is the solution? The solution is to put only one #RunWith() with runner you cannot stand without and replace other one with something else. In your case I guess you will remove MockitoJUnitRunner and do programatically what it does.
In fact the only thing it does it runs:
MockitoAnnotations.initMocks(test);
in the beginning of test case. So, the simplest solution is to put this code into setUp() method:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
I am not sure, but probably you should avoid multiple call of this method using flag:
private boolean mockInitialized = false;
#Before
public void setUp() {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
}
However better, reusable solution may be implemented with JUnt's rules.
public class MockitoRule extends TestWatcher {
private boolean mockInitialized = false;
#Override
protected void starting(Description d) {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
}
}
Now just add the following line to your test class:
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
and you can run this test case with any runner you want.
As of JUnit 4.7 and Mockito 1.10.17, this functionality is built in; there is an org.mockito.junit.MockitoRule class. You can simply import it and add the line
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
to your test class.
This solution works for every possible runner, not just this mockito example. For example; for Spring, just change the runner classes and add necessary annotations.
#RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
#Test
public void subRunner() throws Exception {
JUnitCore.runClasses(TestMockitoJUnitRunner.class);
}
#RunWith(MockitoJUnitRunner.class)
public static class TestMockitoJUnitRunner {
}
}
DatabaseModelTest will be run by JUnit. TestMockitoJUnitRunner depends on it (by logic) and it will be run inside of the main in a #Test method, during the call JUnitCore.runClasses(TestMockitoJUnitRunner.class). This method ensures the main runner is started correctly before the static class TestMockitoJUnitRunner sub-runner runs, effectively implementing multiple nested #RunWith annotations with dependent test classes.
Also on https://bekce.github.io/junit-multiple-runwith-dependent-tests
Since the release of PowerMock 1.6, you can do it as easily as
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
Explained here https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/
In my case I was trying to Mock some method in spring bean and
MockitoAnnotations.initMocks(test);
doesn't works. Instead you have to define that bean to constructed using mock method inside your xml file like following.
...
<bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
</bean>
...
and add that bean with autowired inside your test class like following.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="file:springconfig.xml")
public class TestClass {
...
#Autowired
private ClassWantedToBeMocked classWantedToBeMocked;
...
when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
...
}
check out this link https://bekce.github.io/junit-multiple-runwith-dependent-tests/
using this approach i combined a #RunWith(Parameterized.class) - outer runner - with #RunWith(MockitoJUnitRunner.class) - inner runner. The only tweak i had to add was to make my member variables in the outer class/runner static in order to make them accessible for the inner/nested runner/class. gook luck and enjoy.
I wanted to run SWTBotJunit4ClassRunner and org.junit.runners.Parameterized at the same time, I have parametric tests and I want to screenshots when the SWT test fails (the screenshot feature is provided by the SWTBotJunit4ClassRunner). #bekce's answer is great and first wanted go that route but it was either quirky passing through the arguments. Or doing the parametrized in the subclass and loosing the information what exact tests passed/failed and have only the last screenshot (as the screenshot names get the name from the test itself). So either way it was bit messy.
In my case the SWTBotJunit4ClassRunner is simple enough, so I cloned the source-code of the class, gave it my own name ParametrizedScreenshotRunner and where original was extending the TestRunner, my class is extending the Parameterized class so in essence I can use my own runner instead of the previous two. Boiled down my own runner extends on top of Parameterized runner while implementing the screenshot feature on top of it, now my test use this "hybrid" runner and all the tests work as expected straight away (no need to change anything inside the tests).
This is how it looks like (for sake of brevity I removed all the comments from the listing):
package mySwtTests;
import org.junit.runners.Parameterized;
import org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
public class ParametrizedScreenshotRunner extends TestRu Parameterized {
public ParametrizedScreenshotRunner(Class<?> klass) throws Throwable {
super(klass);
}
public void run(RunNotifier notifier) {
RunListener failureSpy = new ScreenshotCaptureListener();
notifier.removeListener(failureSpy); // remove existing listeners that could be added by suite or class runners
notifier.addListener(failureSpy);
try {
super.run(notifier);
} finally {
notifier.removeListener(failureSpy);
}
}
}
While there are no solution in JUnit 4 it is possible to register multiple extensions in JUnit 5:
#ExtendWith(MockitoExtension.class)
#ExtendWith(AnotherExtension.class)
public class MyTest {
// some tests
}
Note that JUnitParams framework is built into JUnit 5.
You can also try this:
#RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
// some tests
}
#RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
// some tests
}