GithubHelp home page GithubHelp logo

arcbees / jukito Goto Github PK

View Code? Open in Web Editor NEW
270.0 270.0 33.0 531 KB

The combined power of JUnit, Guice and Mockito. Plus it sounds like a cool martial art.

Home Page: http://jukito.arcbees.com/

License: Other

Java 100.00%

jukito's Introduction

Jukito

The combined power of JUnit, Guice and Mockito. Plus it sounds like a cool martial art.


So you started using dependency injection because somebody told you it would make your tests simpler? But as you gaze at your deep hierarchy of test classes, "simple" is not exactly the word you think of. Plus, creating a new mock whenever you add a parameter to an injected constructor gets old very quickly.

You are not alone! And Jukito was created specifically for people like you. Read on, or get started right away!

If you use Google Guice, or if your GWT application uses Gin, then Jukito is the perfect antidote to your unit testing headaches. Now you can write tests like this:

@RunWith(JukitoRunner.class)
public class EmailSystemTest {

  @Inject EmailSystemImpl emailSystem;
  Email dummyEmail;

  @Before
  public void setupMocks(
      IncomingEmails incomingEmails,
      EmailFactory factory) {
    dummyEmail = factory.createDummy();
    when(incomingEmails.count()).thenReturn(1);
    when(incomingEmails.get(0)).thenReturn(dummyEmail);
  }

  @Test
  public void shouldFetchEmailWhenStarting(
      EmailView emailView) {
    // WHEN
    emailSystem.start();

    // THEN
    verify(emailView).addEmail(dummyEmail);
  }
}

That's right, Jukito lets you @Inject fields exactly as if your test class was injected with Guice. You can also inject parameters into your @Test, @Before and @After methods. Guice's just-in-time binding automatically instantiate your concrete classes, like EmailFactory. What about interfaces like IncomingEmails or EmailView? Jukito mocks them out automatically for you using mockito!

Let's look at another example:

@RunWith(JukitoRunner.class)
public class CalculatorTest {

  public static class Module extends JukitoModule {
    protected void configureTest() {
      bindMany(Calculator.class,
          ScientificCalculator.class,
          BusinessCalculator.class);

      bindManyInstances(AdditionExample.class, 
          new AdditionExample(1, 1, 2),
          new AdditionExample(10, 10, 20),
          new AdditionExample(18, 24, 42));
    }
  }

  @Test
  public void testAdd(@All Calculator calculator, @All AdditionExample example) {
    // WHEN
    int result = calculator.add(example.a, example.b);

    // THEN
    assertEquals(example.expected, result);
  }
}

As you see here, Jukito lets you define your very own test module, where you can bind classes just like a regular Guice module. It doesn't stop there, however. The bindMany methods let you bind different classes or instances to the same interface. Combined with the powerful @All annotation this lets you easily run a single test on a whole suite of test examples. The code above will run a total of six tests!

Getting Started

Read the wiki to find out everything Jukito has to offer, and join the discussion!

Latest Release

  • 1.5

Links

Thanks to

Arcbees.com

Atlassian

IntelliJ

jukito's People

Contributors

ahri avatar aldenquimby avatar branflake2267 avatar bryant1410 avatar chris-v avatar christiangoudreau avatar diamondq avatar durron597 avatar jclariviere avatar meriouma avatar olafleur avatar philbeaudoin avatar przemekgalazka avatar the-alchemist avatar yln avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jukito's Issues

Make Jukito work with Spock tests

Hi,

There is already an issue open to have Jukito work with Groovy tests. But, this request is for having Jukito work with Spock tests. If need be I can volunteer to do the coding, since I know Groovy and Spock decently well. But, I would need guidance as to what the design should be since I am brand spanking new to Jukito.

Thanks,
Ravi H

Jukito should give same instances to requested injection and tests

To demonstrate the problem, I made a toy project with these classes:

@Singleton
public class InjectedClass {
    private static int instanceCount = 0;

    public InjectedClass() {
        instanceCount++;
    }
}

public class InjectionReceiver {
    private static int instanceCount = 0;
    private static int injectCount = 0;

    public InjectionReceiver() {
        instanceCount++;
    }

    @Inject
    public void inject(InjectedClass injectedObject) {
        injectCount++;
    }
}

public class InjectingModule extends AbstractModule {
    @Override
    protected void configure() {
        requestInjection(new InjectionReceiver());
    }
}

and this test:

@RunWith(JukitoRunner.class)
public class InjectTest {
    public static class Module extends JukitoModule {
        @Override
        protected void configureTest() {
            install(new InjectingModule());
        }
    }

    @Test
    public void test(InjectedClass injectedObject) {
        int a = 1;
    }
}

When I run the test with break points to follow the execution flow, InjectTest runs its module configuration twice (annoying, but mostly ignorable), which creates two InjectionReceiver objects and requests that each of them get injected. The first never gets injected, I suspect because it gets thrown away and garbage collected.

After this, one instance of InjectedClass is created and passed in to the second InjectionReceiver instance's inject method. Then another instance of InjectedClass is created and that instance is passed in to InjectTest.test. This is a bug.

In my production code, Guice creates only a single instance of the InjectedClass analog, and that same instance is passed in to both the InjectionReceiver.inject analog and every other place the class is called for. This is working correctly, and my code depends on this behavior to function.

In order for my tests to work, they have to have the same instance that is passed in to InjectionReceiver.inject, and they aren't getting it.

@All should not include generated mocks

When a test requires the generation of a mock of the same type as that annotated by "@ALL" the generated mock is added to the list of types generated by the annotation.

e.g.

For the situation where the interface Node is implemented by PlainNode, and the module is configured by

bindMany(Node.class, PlainNode.class);

For the test

public void testAddNeighbour(@All Node n1, Node n2)

n2 will be passed a mock of Node, which is correct, but the test will be executed twice; once with n1 being a PlainNode (as desired) and once with n1 being a mock of Node (not desired).

Release 1.4.1

Release of 1.4.1 after the current pull request merges

Binary incompatibility with Mockito 2.4.0

Mockito 2.4.0 has removed the class org.mockito.internal.runners.util.FrameworkUsageValidator. This means Jukito can only be used with Mockito 2.3.11 or earlier for now.

Should Jukito respect @ImplementedBy?

We have interfaces annotated with @ImplementedBy and the behavior we're observing is that Jukito returns a mock of the interface instead of instantiating the implementation class, is this the expected behavior?

Jukito Cartesian product misfire?

Here's my test class (a node can have a list of neighbours):

@RunWith(JukitoRunner.class)
public class NodeTest {
    public static class Module extends JukitoModule {
        protected void configureTest() {
            bindMany(Node.class, PlainNode.class);
        }
    }

    @Test
    public void testAddNeighbour(@All Node node, Node n2) {
        // Act
        node.addNeighbour(n2);

        // Assert
        assertTrue(node.getClass().getSimpleName(), node.getNeighbours().contains(n2));
    }
}

And I'm getting this failure:

[junit] Testcase: testAddNeighbour took 0.001 sec
[junit] Testcase: testAddNeighbour took 0.007 sec
[junit]     FAILED
[junit] Node$$EnhancerByMockitoWithCGLIB$$7aead885
[junit] junit.framework.AssertionFailedError: Node$$EnhancerByMockitoWithCGLIB$$7aead885
[junit]     at com.kaizen.mapdone.test.NodeTest.testAddNeighbour(NodeTest.java:42)
[junit]     at org.jukito.InjectedStatement.evaluate(InjectedStatement.java:75)
[junit]     at org.jukito.JukitoRunner.run(JukitoRunner.java:166)

So it looks like Jukito is executing the test twice, once with "node" being a mock.

Is this expected behaviour? I'd expect the test to be called once; with params of type (PlainNode, Mock) -- so either I'm confused, or Jukito's doing the wrong thing!

Either resolution is fine by me :)

Jukito & archaius2-guice don't play nicely together

Hi,

I've been investigating an issue with archaius2 & Jukito, where a configuration injected into a component that is initialised by Jukito is provided to the wrong test.

The symptom is that if you use a Config in one test, then all subsequent tests won't have their Config updated:

This test will pass:

@RunWith(JukitoRunner.class)
@UseModules(Module.class)
public class HangingReferenceTest {

    public static class Module extends AbstractModule {
        @Override
        protected void configure() {
            install(new ArchaiusModule() {

                @Override
                protected void configureArchaius() {
                    Map<String, String> configurationValues = new HashMap<>();

                    configurationValues.put("value1", "one");

                    bindDefaultConfig().toInstance(MapConfig.from(configurationValues));
                }
            });
        }

    }
    
    @Inject
    Provider<Config> configProvider;

    @Test
    public void testConfig() {
        assertThat(configProvider.get().getString("value1"), is("one"));
    }

}

But this test will fail, and if you look through the values of the Config, it just has "value1":

@RunWith(JukitoRunner.class)
@UseModules(Module.class)
public class HangingReference2Test {

    public static class Module extends AbstractModule {
        @Override
        protected void configure() {
            install(new ArchaiusModule() {

                @Override
                protected void configureArchaius() {
                    Map<String, String> configurationValues = new HashMap<>();

                    configurationValues.put("value2", "two");

                    bindDefaultConfig().toInstance(MapConfig.from(configurationValues));
                }
            });
        }

    }

    @Inject
    Provider<Config> configProvider;

    @Test
    public void testConfig() {
        assertThat(configProvider.get().getString("value2"), is("two"));
    }

}

I've been digging around in Jukito and have tracked it down to this bit of code in JukitoModule:

        // Make sure needed keys from Guice bindings are bound as mock or to instances
        // (but not as test singletons)
        for (Key<?> keyNeeded : keysNeeded) {
            addNeededKey(keysObserved, keysNeeded, keyNeeded, false);
            keysNeedingTransitiveDependencies.add(keyNeeded);
        }

Is there a particular reason that you force bind in concrete instances that Jukito observes? Guice should provide them regardless and if I change the code to the follwing then everything is fine in archaius2 and also in your unit tests:

    // Make sure needed keys from Guice bindings are bound as mock or to instances
    // (but not as test singletons)
    for (Key<?> keyNeeded : keysNeeded) {
      TypeLiteral<?> typeToBind = keyNeeded.getTypeLiteral();
      Class<?> rawType = typeToBind.getRawType();
      if (!keysObserved.contains(keyNeeded) && canBeInjected(typeToBind)
          && !shouldForceMock(rawType) && !isAssistedInjection(keyNeeded)) {
        keysObserved.add(keyNeeded);
      }
      keysNeedingTransitiveDependencies.add(keyNeeded);
    }

Thanks in advance.

Jukito does not work well with ExpectedException rule

Using ExpectedException to test for expected exception does not work as intended, as Jukito's InjectedAfterStatements.evaluate() wraps and rethrows all exceptions as org.junit.internal.runners.model.MultipleFailureException.MultipleFailureException(List<Throwable>)

This behavior would be ok for multiple exceptions, e.g. when also catching Guice-related exceptions in addition to exceptions which occurred in the actual test. But when there is only one exception, this should be re-thrown directly instead of wrapping it into MultipleFailureException.

This can actually easily be done by using org.junit.runners.model.MultipleFailureException.assertEmpty(List<Throwable>) which first checks if there is only a single exception and if so rethrows it directly. Multiple exceptions are still wrapped into a MultipleFailureException as it used to be in Jukito.

Using requestStaticInjection doesn't inject mock as expected

In the code snippet bellow, we need to manually provide binding for all abstraction.

   public static class Module extends JukitoModule {
        @Override
        protected void configureTest() {
            requestStaticInjection(AbstractAsyncCallback.class);
        }

        @Provides
        @Singleton
        private Console getConsole() {
            return mock(Console.class);
        }

        @Provides
        @Singleton
        private EventBus getEventbus() {
            return mock(EventBus.class);
        }

        @Provides
        @Singleton
        private ResMessages getResMessage() {
            return mock(ResMessages.class);
        }

        @Provides
        @Singleton
        private PlaceManager getPlaceManager() {
            return mock(PlaceManager.class);
        }
    }

Binding modules doesn't seem to work (v 1.4 and snapshot, Java 8)

Test Class:

@RunWith(JukitoRunner.class)
@UseModules({ CoreInjectionBasedTest.class})
public class InventoryHolderAspectTest{

@Test
public void test (){
}

}

////////

Module Class:

public class CoreInjectionBasedTest extends JukitoModule {

@Override
protected void configureTest() {
}

}

////////

There doesn't seem to be anything to fail, yet it somehow does, with runtime error:

java.lang.RuntimeException: com.google.inject.CreationException: Unable to create injector, see the following errors:

  1. Scope TestSingleton is already bound to org.jukito.TestSingleton at org.jukito.TestModule.bindScopes(TestModule.java:55).
    Cannot bind TestSingleton.
    at org.jukito.TestModule.bindScopes(TestModule.java:55) (via modules: org.jukito.JukitoRunner$3 -> pyramide9.testutils.CoreInjectionBasedTest)

  2. Scope EagerTestSingleton is already bound to org.jukito.TestEagerSingleton at org.jukito.TestModule.bindScopes(TestModule.java:56).
    Cannot bind EagerTestSingleton.
    at org.jukito.TestModule.bindScopes(TestModule.java:56) (via modules: org.jukito.JukitoRunner$3 -> pyramide9.testutils.CoreInjectionBasedTest)

2 errors
at org.jukito.JukitoRunner.computeTestMethods(JukitoRunner.java:235)
at org.jukito.JukitoRunner.validateInstanceMethods(JukitoRunner.java:369)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:104)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:355)
at org.junit.runners.ParentRunner.(ParentRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.(BlockJUnit4ClassRunner.java:57)
at org.jukito.JukitoRunner.(JukitoRunner.java:75)
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:408)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21)
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:26)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.(JUnit4TestReference.java:33)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.(JUnit4TestClassReference.java:25)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:444)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors:

  1. Scope TestSingleton is already bound to org.jukito.TestSingleton at org.jukito.TestModule.bindScopes(TestModule.java:55).
    Cannot bind TestSingleton.
    at org.jukito.TestModule.bindScopes(TestModule.java:55) (via modules: org.jukito.JukitoRunner$3 -> pyramide9.testutils.CoreInjectionBasedTest)

  2. Scope EagerTestSingleton is already bound to org.jukito.TestEagerSingleton at org.jukito.TestModule.bindScopes(TestModule.java:56).
    Cannot bind EagerTestSingleton.
    at org.jukito.TestModule.bindScopes(TestModule.java:56) (via modules: org.jukito.JukitoRunner$3 -> pyramide9.testutils.CoreInjectionBasedTest)

2 errors
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:448)
at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:155)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107)
at com.google.inject.Guice.createInjector(Guice.java:99)
at com.google.inject.Guice.createInjector(Guice.java:73)
at com.google.inject.Guice.createInjector(Guice.java:62)
at org.jukito.JukitoRunner.ensureInjector(JukitoRunner.java:105)
at org.jukito.JukitoRunner.computeTestMethods(JukitoRunner.java:233)

I can provide a reproduction project if that would be useful.

Gradle 5.1 breaks Jukito's @All when using JUnit 5 useJUnitPlatform

Here's a minimal failing project: https://github.com/slayful/minimal-jukito-gradle-5.1-failing-project
I'm suspecting there's an issue when generating test cases or their names, maybe.
Here's the stack trace with the issue.

java.lang.AssertionError
	at org.gradle.api.internal.tasks.testing.processors.TestOutputRedirector.setOutputOwner(TestOutputRedirector.java:49)
	at org.gradle.api.internal.tasks.testing.processors.CaptureTestOutputTestResultProcessor.completed(CaptureTestOutputTestResultProcessor.java:80)
	at org.gradle.api.internal.tasks.testing.results.AttachParentTestResultProcessor.completed(AttachParentTestResultProcessor.java:56)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.actor.internal.DefaultActorFactory$BlockingActor.dispatch(DefaultActorFactory.java:122)
	at org.gradle.internal.actor.internal.DefaultActorFactory$BlockingActor.dispatch(DefaultActorFactory.java:97)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy3.completed(Unknown Source)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener.executionFinished(JUnitPlatformTestExecutionListener.java:110)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.lambda$executionFinished$5(TestExecutionListenerRegistry.java:92)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry.notifyTestExecutionListeners(TestExecutionListenerRegistry.java:59)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry.access$100(TestExecutionListenerRegistry.java:28)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.executionFinished(TestExecutionListenerRegistry.java:92)
	at org.junit.platform.launcher.core.ExecutionListenerAdapter.executionFinished(ExecutionListenerAdapter.java:56)
	at org.junit.vintage.engine.execution.RunListenerAdapter.fireExecutionFinished(RunListenerAdapter.java:202)
	at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:160)
	at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:76)
	at org.junit.runner.notification.SynchronizedRunListener.testFinished(SynchronizedRunListener.java:56)
	at org.junit.runner.notification.RunNotifier$7.notifyListener(RunNotifier.java:190)
	at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:72)
	at org.junit.runner.notification.RunNotifier.fireTestFinished(RunNotifier.java:187)
	at org.junit.internal.runners.model.EachTestNotifier.fireTestFinished(EachTestNotifier.java:38)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:331)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.jukito.JukitoRunner.run(JukitoRunner.java:227)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:39)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:79)
	at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:70)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:102)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:82)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:78)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.base/java.lang.Thread.run(Thread.java:834)

JukitoRunner doesn't support PrivateModule bindings

Against Jukito 1.3, when using a PrivateModule, the JukitoRunner doesn't collect the exposed bindings, so any @injects in the test case are enhanced with a mock object (since it isn't aware of the bindings).

Unfortunately, this means that a second binding is added to the injector, and Guice throws a duplicate binding error:

java.lang.RuntimeException: com.google.inject.CreationException: Guice creation errors:

1) A binding to java.lang.String annotated with @com.google.inject.name.Named(value=test) was already configured at TestPrivate$Module.configure(TestPrivate.java:26).
...

Test case that fails:

@RunWith(JukitoRunner.class)
@UseModules(Module.class)
public class TestPrivate {
    public static class Module extends PrivateModule {

        @Override
        protected void configure() {

            bindConstant().annotatedWith(Names.named("test")).to("Test String");
            expose(String.class).annotatedWith(Names.named("test"));
        }
    }

    @Inject
    @Named("test")
    String  testString;

    @Test
    public void privateModuleTest() {

        /* Make sure that it's not a mocked object */

        assertFalse(Mockito.mockingDetails(testString).isMock());

        assertEquals("Test String", testString);
    }

}

No way to provide on the fly bindings instead of the plain mocks jukito binds

Use case:
For example in GWT code you might have a page full of field widgets like input boxes and radio buttons etc.

They might all implement IsWidget interface and HasValue<?> interface. Instead of getting a regular mock. A jukito test might want to detect required bindings like this and bind a mock that responds correctly to setValue() and getValue() methods.

My main issue is with the JukitoModule. everything is protected and/or final.

It would be nice if instead of:
bind(key).toProvider(new MockProvider(rawType)).in(TestScope.SINGLETON);

It was bind(key).toProvider(getProviderForKey(key)).in(TestScope.SINGLETON);

Where getProviderForKey was protected and not final. What do you think? Would you accept a patch like this?

"already configured" error with PrivateModules and annotated bindings

Originally posted to Google Group

I'm trying to use Jukito in a complicated situation which consists of multiple PrivateModules and annotated bindings, but it doesn't work and looking for a help.

I pushed the reproducer and full stacktrace to https://github.com/lbtc-xxx/jukito-error . This problem can be reproduced with cloning this repo and simply executing mvn clean test.

This yields a CreationException which states "... A binding to app.ThirdPartyService was already configured at ...". But there is no duplicated binding in my modules, so it works well with Guice.createInjector().getInstance().

I created and exposed one annotated binding and one not annotated binding in a PrivateModule, and apparently it doesn't play well with Jukito.

Is there any workaround to this situation?

Add the posibility to use @Before with bindMany

bindMany and All annotation doesn't permit to setup up the binded instance with a before annotated method.
The following code demonstrate the use case:

import org.jukito.All;
import org.jukito.JukitoModule;
import org.jukito.JukitoRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

interface TestInterface {
  void foo();
}
class ImplOne implements TestInterface {
  public void foo() {
  }
}

class ImplTwo implements TestInterface {
  public void foo() {
  }
}

@RunWith(JukitoRunner.class)
public class BindManyTest {

  public static class Module extends JukitoModule {

    @Override
    protected void configureTest() {
      bindMany(TestInterface.class, ImplOne.class, ImplTwo.class);
    }
  }

  @Before
  public void setup(TestInterface test) {
    System.out.println(test.getClass().getSimpleName());
  }

  @Test
  public void testGetFlight(@All TestInterface test) {
    System.out.println(test.getClass().getSimpleName());
  }
}

When running the test I expect as output:

ImplOne
ImplOne
ImplTwo
ImplTwo

Instead the output is:

TestInterface$$EnhancerByMockitoWithCGLIB$$78a15e3b
ImplOne
TestInterface$$EnhancerByMockitoWithCGLIB$$78a15e3b
ImplTwo

It's possible to support the All annotation also in Before method or fix the behavior?

Injecting inner classes doesn't give an informative error message.

Guice doesn't support injections into inner classes. It gives an informative error message about why. But, if you try to do the same thing with Jukito, you get little; Jukito will inject a mock of the instance that Guice was not able to create. Here's an example:

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class InnerGuiceExample {
    public static class Module extends AbstractModule {
        @Override
        protected void configure() {
            bind(String.class).toInstance("hello world!");
        }
    }

    Foo f;

    @Before
    public void setUp() {
        Injector inj = Guice.createInjector(new Module());
        f = inj.getInstance(Foo.class);
    }

    @Test
    public void test() {
        assertEquals("hello world!", f.toString());
    }

    public class Foo {
        @Inject String test;

        public String toString() {
            return test;
        }
    }
}

And Guice's error message:

com.google.inject.ConfigurationException: Guice configuration errors:

1) Injecting into inner classes is not supported.  Please use a 'static' class (top-level or nested) instead of com.techemet.server.InnerGuiceExample$Foo.
  while locating com.techemet.server.InnerGuiceExample$Foo

1 error
    at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
    at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
    at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
    at com.techemet.server.InnerGuiceExample.setUp(InnerGuiceExample.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    ...

Here's the Jukito equivalent of the same code:

import static org.junit.Assert.*;

import org.jukito.JukitoModule;
import org.jukito.JukitoRunner;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.google.inject.Inject;

@RunWith(JukitoRunner.class)
public class InnerJukitoExample {
    public static class Module extends JukitoModule {
        @Override
        protected void configureTest() {
            bind(String.class).toInstance("hello world!");
        }
    }

    @Inject Foo f;

    @Test
    public void test() {
        assertEquals("hello world!", f.toString());
    }

    public class Foo {
        @Inject String test;

        public String toString() {
            return test;
        }
    }
}

With error message:

org.junit.ComparisonFailure: expected:<[hello world!]> but was:<[Mock for Foo, hashCode: 936146014]>
    at org.junit.Assert.assertEquals(Assert.java:115)
    at org.junit.Assert.assertEquals(Assert.java:144)
    at com.techemet.server.InnerJukitoExample.test(InnerJukitoExample.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Jukito doesn't seem to properly honor private modules.

Not sure if the project is still being maintained, last commit looks like it was a couple years ago.. but here's hoping ๐Ÿ˜„

I use private modules quite extensively in my projects to keep bindings as local as possible, however, I've noticed that if I install a private module in a Jukito test, classes that should be able to be injected with those bindings get mocks instead of the proper bindings. Creating a regular Guice injector and obtaining an instance of the same class sees the bindings as expected.

An example:

class ExampleModule extends PrivateModule {
    // Some thing that I'm testing.
    bind(ExampleInterface.class).to(ExampleImpl.class);
    expose(ExampleInterface.class);

    // Purposely not exposed.
    bind(PrivateInnerInterface.class).to(PrivateInnerImpl.class);
}

// elsewhere in test land:
public static class Module extends JukitoModule {

    @Override
    public void configureBindings() {
        install(new ExampleModule());
    }


    @Test
    public void testSomething(ExampleInterface example) {
        // ExampleInterface is concrete, as expected, but was injected with a
        // mock of PrivateInnerInterface, even though I'd expect it should
        // have a PrivateInnerImpl.
    }

}

Is this expected behavior? A limitation of the binding not being exposed?

Jukito shouldn't inject optional injection points

I'm using a third-party library that uses Guice (Closure Templates) and makes use of optional injection:

  @Inject(optional = true)
  void setCheckConformance(CheckConformance checkConformance) {
    this.checkConformance = checkConformance;
  }

Unfortunately, Jukito will inject a mock CheckConformance which will later cause issues because the contract for the interface is to never return a null, causing a NullPointerException when the mock breaks that contract:

    if (checkConformance != null) {
      ImmutableList<SoySyntaxException> violations = checkConformance.getViolations(soyTree);
      if (!violations.isEmpty()) {

Jukito shouldn't inject such injection points with mocks unless bind() or forceMock() has been called for the key.

The workaround in my case is to explicitly bind CheckConformance to a dummy instance (or configure the mock) to make sure it never return nulls.

Guice modules configured twice

When using @UseModules and @RunWith(JukitoRunner.class), the method JukitoRunner#ensureInjector configures all guice modules twice.

It looks like a second test module is created and configured to "collect bindings," and it appears to be intentional based on this comment.

Is this necessary? Is there any way to reuse the existing test module? It's pretty confusing to have every registered module configured twice.

Support @Provides methods for specifying instances to @All injected tests

Instead of

public static Module extends TestModule {
  protected void configureTest() {
    bindMany(SomeInterface.class, Impl1.class, Impl2.class);
  }
}
...
@Test
someTest(@All SomeInterface interface) {
 ...
}

I would like to be able to do:

public static Module extends TestModule {
  protected void configureTest() {
    install(new SharedModule());
  }

  @Provides
  @Instance
  SomeInterface  provideImpl1() {   
    return new Impl1();
  }

  @Provides
  @Instance
  SomeInterface provideImpl2(final SomeTypeFromSharedModule info) {
    return new Impl2(info.get());
  }
}
...
@Test
someTest(@All SomeInterface interface) {
 ...
}

As you can see, the latter approach allows me to construct test instances using info from other injected types, whereas the current approach doesn't allow me access to other types that may have been installed.

Also, it would be great to specify the test name for the junit runner, perhaps on the @Instance annotation.

@UseModules on test method does not create mocks

I am trying to create a test where I have a @UseModules on a test mode to setup a dependency different from other test methods. But as a consequence objects are not mocked as is the case with using the @UseModules on the test class.

This unit test show It in action. The testWithoutUseModules gets a mocked HttpServletRequest, while the testWithUseModules gives a Guice error that no implementation was bound for the HttpServletRequest parameter. Maybe I am misreading or misunderstanding it.

@RunWith(JukitoRunner.class)
@UseModules(MockingTest.ModuleA.class)
public class MockingTest {
  @Test
  public void testWithoutUseModules(HttpServletRequest request) {
    assertNotNull(request);
  }

  @Test
  @UseModules(ModuleB.class)
  public void testWithUseModules(HttpServletRequest request) {
    assertNotNull(request);
  }
  public static class ModuleA extends AbstractModule {
    @Override
    protected void configure() {
    }
  }

  public static class ModuleB extends AbstractModule {
    @Override
    protected void configure() {
    }
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.