Repository: ArcBees/Jukito Branch: master Commit: 280d16cf220e Files: 85 Total size: 266.5 KB Directory structure: gitextract_98m20j73/ ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── codequality/ │ ├── checkstyle.xml │ ├── opensource.java.header │ └── suppressions.xml ├── jukito/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── org/ │ │ └── jukito/ │ │ ├── All.java │ │ ├── BindingsCollector.java │ │ ├── Description.java │ │ ├── EnvironmentDependentModules.java │ │ ├── GuiceUtils.java │ │ ├── InjectedAfterStatements.java │ │ ├── InjectedBeforeStatements.java │ │ ├── InjectedFrameworkMethod.java │ │ ├── InjectedStatement.java │ │ ├── JukitoInternal.java │ │ ├── JukitoModule.java │ │ ├── JukitoRunner.java │ │ ├── MockProvider.java │ │ ├── MockitoUsageValidator.java │ │ ├── NamedUniqueAnnotations.java │ │ ├── SpyImmutableInstanceProvider.java │ │ ├── SpyProvider.java │ │ ├── TestEagerSingleton.java │ │ ├── TestMockSingleton.java │ │ ├── TestModule.java │ │ ├── TestScope.java │ │ ├── TestSingleton.java │ │ └── UseModules.java │ └── test/ │ └── java/ │ └── org/ │ └── jukito/ │ ├── AllAnnotationTest.java │ ├── AllNamedAnnotationTest.java │ ├── AssistedInjectTest.java │ ├── AutoBindMocksDisabledTest.java │ ├── BindAnnotatedConcreteClassesTest.java │ ├── BindSpyInstanceTest.java │ ├── BindSpyTest.java │ ├── BindingToProviderTest.java │ ├── EDRunner.java │ ├── EnvironmentDependentComponent.java │ ├── ExternalSingleton.java │ ├── ForceMockTest.java │ ├── GeneralTest.java │ ├── InnerClassTest.java │ ├── InstallTest.java │ ├── ModuleWithProvidesMethods.java │ ├── NoModuleTest.java │ ├── OldStyleAssistedInjectTest.java │ ├── OneHundred.java │ ├── ParentClassInnerClassModuleDiscoveryTest.java │ ├── ParentTestClassBase.java │ ├── ParentTestClassTest.java │ ├── ProviderBindingTest.java │ ├── ProviderTest.java │ ├── ProvidesMethodTest.java │ ├── ReportWriterTest.java │ ├── RequestInjectionTest.java │ ├── RequestStaticInjectionTest.java │ ├── RespectProvidesAnnotationInModuleTest.java │ ├── RespectTestScopeWhenUsingAbstractModuleTest.java │ ├── SampleParentTestClassWithInnerTestModule.java │ ├── SingletonTest.java │ ├── SomeCoreComponent.java │ ├── SomeTestClass.java │ ├── TestTestDescriptions.java │ ├── TransitiveDependencyTest.java │ ├── UseModulesTest.java │ ├── Value3.java │ └── environmentdependent/ │ ├── DesktopModule.java │ ├── EnvironmentDependentModulesTest.java │ ├── MobileModule.java │ └── TabletModule.java ├── jukito-samples/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── org/ │ │ └── jukito/ │ │ └── samples/ │ │ ├── Car.java │ │ ├── DieselEngine.java │ │ ├── Engine.java │ │ ├── FordMustang.java │ │ ├── PetrolEngine.java │ │ └── modules/ │ │ ├── DieselLineModule.java │ │ └── PetrolLineModule.java │ └── test/ │ └── java/ │ └── org/ │ └── jukito/ │ └── samples/ │ ├── FordMustangTest.java │ ├── FordMustangTest2.java │ └── FordMustangTest3.java └── pom.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ gwt-unitCache www-test target .project *.iml .settings .idea .classpath .gwt bin META-INF .checkstyle ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing ================================================ FILE: LICENSE.md ================================================ # License Jukito is freely distributable under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html). ================================================ FILE: README.md ================================================ ![Jukito](http://i.imgur.com/rSeHAEc.png "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](https://github.com/ArcBees/Jukito/wiki) right away! If you use [Google Guice](http://code.google.com/p/google-guice/), or if your GWT application uses [Gin](http://code.google.com/p/google-gin/), then Jukito is the perfect antidote to your unit testing headaches. Now you can write tests like this: ```java @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](https://code.google.com/p/mockito/)! Let's look at another example: ```java @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](https://github.com/ArcBees/Jukito/wiki) to find out everything Jukito has to offer, and [join the discussion](http://groups.google.com/group/jukito)! ## Latest Release * 1.5 ## Links * [Jukito Custom Google Search](http://www.google.com/cse/home?cx=011138278718949652927:turyqq9pl64) - Search GWTP documentation, wiki and thread collections. * [Jukito WebSite Source](https://github.com/ArcBees/jukito-website) - Jukito website source. * [Jukito Google Group](https://groups.google.com/forum/?fromgroups#!forum/jukito) - Find help here. * [Jukito Previous Repo](https://code.google.com/p/jukito/) - Previous home of Jukito. * [GWTP](https://github.com/ArcBees/GWTP) - Find out more about GWT-Platform. ## Thanks to [![Arcbees.com](http://i.imgur.com/HDf1qfq.png)](http://arcbees.com) [![Atlassian](http://i.imgur.com/BKkj8Rg.png)](https://www.atlassian.com/) [![IntelliJ](https://lh6.googleusercontent.com/--QIIJfKrjSk/UJJ6X-UohII/AAAAAAAAAVM/cOW7EjnH778/s800/banner_IDEA.png)](http://www.jetbrains.com/idea/index.html) ================================================ FILE: codequality/checkstyle.xml ================================================ ================================================ FILE: codequality/opensource.java.header ================================================ /\*\*? \* Copyright \d{4} ArcBees Inc\. \* \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not \* use this file except in compliance with the License\. You may obtain a copy of \* the License at \* \* http://www\.apache\.org/licenses/LICENSE-2\.0 \* \* Unless required by applicable law or agreed to in writing, software \* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the \* License for the specific language governing permissions and limitations under \* the License\. \*/ ================================================ FILE: codequality/suppressions.xml ================================================ ================================================ FILE: jukito/pom.xml ================================================ 4.0.0 org.jukito jukito-parent 1.6-SNAPSHOT jukito jar jukito org.apache.maven.plugins maven-compiler-plugin org.apache.maven.plugins maven-surefire-plugin org.apache.maven.plugins maven-deploy-plugin org.apache.maven.plugins maven-checkstyle-plugin org.apache.maven.plugins maven-source-plugin org.apache.maven.plugins maven-release-plugin org.codehaus.mojo animal-sniffer-maven-plugin org.apache.maven.plugins maven-javadoc-plugin com.github.github site-maven-plugin org.mockito mockito-core junit junit com.google.inject guice com.google.inject.extensions guice-assistedinject ================================================ FILE: jukito/src/main/java/org/jukito/All.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.BindingAnnotation; /** * This annotation can be used on one or more parameter of a test function. * The test function will be executed multiple times, one for each value bound * to the parameter type. *

* If more than one parameter is annotated with {@literal @}{@link All} then * all combinations will be used. Therefore, be careful when using it on more than * two or three parameters as it can result in a combinatorial explosion. *

* Using the additional parameter {@link #value()} a subset of all bound values * can be specified to be run in the test function. * * @see {@link TestModule#bindMany} * @see {@link TestModule#bindManyInstances} * @see {@link TestModule#bindManyNamed} * @see {@link TestModule#bindManyNamedInstances} */ @BindingAnnotation @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface All { String DEFAULT = "__ALL__"; /** * Used in conjunction with {@link org.jukito.JukitoModule#bindManyNamed(Class, String, Class[])} and related * methods to retrieve all objects binded with the given name. */ String value() default DEFAULT; } ================================================ FILE: jukito/src/main/java/org/jukito/BindingsCollector.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Set; import com.google.inject.AbstractModule; import com.google.inject.Binding; import com.google.inject.Key; import com.google.inject.Scope; import com.google.inject.spi.ConstructorBinding; import com.google.inject.spi.ConvertedConstantBinding; import com.google.inject.spi.DefaultBindingScopingVisitor; import com.google.inject.spi.DefaultBindingTargetVisitor; import com.google.inject.spi.DefaultElementVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.InstanceBinding; import com.google.inject.spi.LinkedKeyBinding; import com.google.inject.spi.Message; import com.google.inject.spi.PrivateElements; import com.google.inject.spi.ProviderBinding; import com.google.inject.spi.ProviderInstanceBinding; import com.google.inject.spi.ProviderKeyBinding; import com.google.inject.spi.StaticInjectionRequest; import com.google.inject.spi.UntargettedBinding; /** * Collects all the bindings from a Guice module, so that Jukito can identify missing * bindings and bind them to mock or instances. */ public class BindingsCollector { /** * Information on a binding, used by Jukito to identify provided keys and needed keys. */ public static class BindingInfo { public Object boundInstance; Key key; Key boundKey; String scope; public static BindingInfo create(Binding binding, Key boundKey, Object instance) { BindingInfo bindingInfo = new BindingInfo(); bindingInfo.key = binding.getKey(); bindingInfo.boundKey = boundKey; bindingInfo.boundInstance = instance; bindingInfo.scope = binding.acceptScopingVisitor(new GuiceScopingVisitor()); return bindingInfo; } public static BindingInfo create(Key boundKey) { BindingInfo bindingInfo = new BindingInfo(); bindingInfo.boundKey = boundKey; return bindingInfo; } } private final AbstractModule module; private final List bindingsObserved = new ArrayList<>(); private final List messages = new ArrayList<>(); BindingsCollector(AbstractModule module) { this.module = module; } public void collectBindings() { GuiceElementVisitor visitor = new GuiceElementVisitor(); visitor.visitElements(Elements.getElements(module)); // TODO report errors? } public List getBindingsObserved() { return bindingsObserved; } /** * This visitor collects all information on various guice elements. */ public class GuiceElementVisitor extends DefaultElementVisitor { private void visitElements(List elements) { for (Element element : elements) { element.acceptVisitor(this); } } @Override public Void visit(com.google.inject.Binding command) { GuiceBindingVisitor bindingVisitor = new GuiceBindingVisitor<>(); command.acceptTargetVisitor(bindingVisitor); return null; } @SuppressWarnings("unchecked") @Override public Void visit(PrivateElements privateElements) { Set> exposedKeys = privateElements.getExposedKeys(); for (Element element : privateElements.getElements()) { if (element instanceof Binding) { Binding bindingElement = (Binding) element; if (exposedKeys.contains(bindingElement.getKey())) { @SuppressWarnings("rawtypes") GuicePrivateBindingVisitor bindingVisitor = new GuicePrivateBindingVisitor(); bindingElement.acceptTargetVisitor(bindingVisitor); } } } return null; } @Override public Void visit(StaticInjectionRequest staticInjectionRequest) { for (InjectionPoint injectionPoint : staticInjectionRequest.getInjectionPoints()) { addInjectionPointDependencies(injectionPoint); } return super.visit(staticInjectionRequest); } @Override public Void visit(Message message) { messages.add(message); return null; } private void addInjectionPointDependencies(InjectionPoint injectionPoint) { // Do not consider dependencies coming from optional injections. if (injectionPoint.isOptional()) { return; } for (Dependency dependency : injectionPoint.getDependencies()) { Key key = dependency.getKey(); bindingsObserved.add(BindingInfo.create(key)); } } } /** * This visitor collects all information on guice bindings. */ public class GuiceBindingVisitor extends DefaultBindingTargetVisitor { protected Void addBindingInfo(Binding binding, Key boundKey, Object instance) { bindingsObserved.add(BindingInfo.create(binding, boundKey, instance)); return null; } private Void addBinding(Binding binding) { return addBindingInfo(binding, binding.getKey(), null); } private Void addBindingKey(Binding binding, Key boundKey) { return addBindingInfo(binding, boundKey, null); } private Void addBindingInstance(Binding binding, Object instance) { return addBindingInfo(binding, null, instance); } @Override public Void visit(ProviderBinding providerBinding) { return addBindingKey(providerBinding, providerBinding.getProvidedKey()); } @Override public Void visit(ProviderKeyBinding providerKeyBinding) { return addBindingKey(providerKeyBinding, providerKeyBinding.getProviderKey()); } @Override public Void visit(ProviderInstanceBinding providerInstanceBinding) { return addBindingInstance(providerInstanceBinding, providerInstanceBinding.getProviderInstance()); } @Override public Void visit(InstanceBinding instanceBinding) { return addBindingInstance(instanceBinding, instanceBinding.getInstance()); } @Override public Void visit(ConvertedConstantBinding constantBinding) { return addBindingInstance(constantBinding, constantBinding.getValue()); } @Override public Void visit(UntargettedBinding untargettedBinding) { return addBinding(untargettedBinding); } @Override public Void visit(LinkedKeyBinding linkedKeyBinding) { return addBindingKey(linkedKeyBinding, linkedKeyBinding.getLinkedKey()); } @Override public Void visit(ConstructorBinding constructorBinding) { return addBinding(constructorBinding); } } /** * This visitor collects the bindings for PrivateModules. Because the child * elements are private, the bound keys are not recorded. */ public class GuicePrivateBindingVisitor extends GuiceBindingVisitor { @Override public Void visit(LinkedKeyBinding linkedKeyBinding) { return addBindingInfo(linkedKeyBinding, null, null); } } /** * This visitor collects all information on guice scopes associated to the bindings. */ public static class GuiceScopingVisitor extends DefaultBindingScopingVisitor { @Override public String visitEagerSingleton() { return "EagerSingleton"; } @Override public String visitScope(Scope scope) { return scope.toString(); } @Override public String visitScopeAnnotation(Class scopeAnnotation) { return scopeAnnotation.getCanonicalName(); } } } ================================================ FILE: jukito/src/main/java/org/jukito/Description.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation can be used for better test description (instead of camel case test method). */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Description { String value(); } ================================================ FILE: jukito/src/main/java/org/jukito/EnvironmentDependentModules.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.Module; /** * Annotation used for declaration of modules which are installed * and used separately in different applications * but test for it collaborators are the same and thus * run for against Environment Dependent Modules. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EnvironmentDependentModules { Class[] value(); } ================================================ FILE: jukito/src/main/java/org/jukito/GuiceUtils.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import com.google.inject.ConfigurationException; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.TypeLiteral; import com.google.inject.internal.Annotations; import com.google.inject.internal.Errors; import com.google.inject.internal.ErrorsException; /** * A number of useful static methods to manipulate Guice object. Most are * taken from the source code of Guice, but cannot be accessed in there. */ public class GuiceUtils { public static boolean isProvider(Key key) { return key.getTypeLiteral().getRawType().equals(Provider.class); } @SuppressWarnings("unchecked") public static TypeLiteral getProvidedType( TypeLiteral> initialProviderTypeLiteral, Errors errors) throws ErrorsException { TypeLiteral> providerTypeLiteral = initialProviderTypeLiteral; while (providerTypeLiteral.getRawType() != Provider.class) { providerTypeLiteral = (TypeLiteral>) providerTypeLiteral.getSupertype(Provider.class); } Type providerType = providerTypeLiteral.getType(); // If the Provider has no type parameter (raw Provider)... if (!(providerType instanceof ParameterizedType)) { throw errors.cannotInjectRawProvider().toException(); } Type entryType = ((ParameterizedType) providerType).getActualTypeArguments()[0]; return (TypeLiteral) TypeLiteral.get(entryType); } public static Key getProvidedKey(Key> key, Errors errors) throws ErrorsException { TypeLiteral providedType = getProvidedType(key.getTypeLiteral(), errors); Key providedKey; if (key.getAnnotation() == null) { providedKey = (Key) Key.get(providedType); } else { providedKey = (Key) Key.get(providedType, key.getAnnotation()); } return providedKey; } @SuppressWarnings("unchecked") public static Key ensureProvidedKey(Key key, Errors errors) { try { return isProvider(key) ? getProvidedKey((Key>) key, errors) : key; } catch (ConfigurationException e) { errors.merge(e.getErrorMessages()); } catch (ErrorsException e) { errors.merge(e.getErrors()); } return null; } public static List> getMethodKeys(Method method, Errors errors) { Annotation allParameterAnnotations[][] = method.getParameterAnnotations(); List> result = new ArrayList>(allParameterAnnotations.length); Iterator annotationsIterator = Arrays.asList(allParameterAnnotations).iterator(); TypeLiteral type = TypeLiteral.get(method.getDeclaringClass()); for (TypeLiteral parameterType : type.getParameterTypes(method)) { try { Annotation[] parameterAnnotations = annotationsIterator.next(); result.add(Annotations.getKey(parameterType, method, parameterAnnotations, errors)); } catch (ConfigurationException e) { errors.merge(e.getErrorMessages()); } catch (ErrorsException e) { errors.merge(e.getErrors()); } } return result; } } ================================================ FILE: jukito/src/main/java/org/jukito/InjectedAfterStatements.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.ArrayList; import java.util.List; import org.junit.internal.runners.model.MultipleFailureException; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import com.google.inject.Injector; /** * A {@link Statement} invoking a list of methods with parameters by filling-in * these parameters with injected instances. The methods are called after the * provided {@code prev} {@link Statement}. */ public class InjectedAfterStatements extends Statement { private final Statement prev; private final List afters; public InjectedAfterStatements(Statement prev, List afters, Object target, Injector injector) { this.prev = prev; this.afters = new ArrayList(afters.size()); for (FrameworkMethod method : afters) { this.afters.add(new InjectedStatement(method, target, injector)); } } @Override public void evaluate() throws Throwable { List errors = new ArrayList(); errors.clear(); try { prev.evaluate(); } catch (Throwable e) { errors.add(e); } finally { for (Statement after : afters) { try { after.evaluate(); } catch (Throwable e) { errors.add(e); } } } if (!errors.isEmpty()) { throw new MultipleFailureException(errors); } } } ================================================ FILE: jukito/src/main/java/org/jukito/InjectedBeforeStatements.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.ArrayList; import java.util.List; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import com.google.inject.Injector; /** * A {@link Statement} invoking a list of methods with parameters by filling-in * these parameters with injected instances. The methods are called before the * provided {@code next} {@link Statement}. */ public class InjectedBeforeStatements extends Statement { private final Statement next; private final List befores; public InjectedBeforeStatements(Statement next, List befores, Object target, Injector injector) { this.next = next; this.befores = new ArrayList(befores.size()); for (FrameworkMethod method : befores) { this.befores.add(new InjectedStatement(method, target, injector)); } } @Override public void evaluate() throws Throwable { for (Statement before : befores) { before.evaluate(); } next.evaluate(); } } ================================================ FILE: jukito/src/main/java/org/jukito/InjectedFrameworkMethod.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.reflect.Method; import java.util.List; import org.junit.runners.model.FrameworkMethod; import com.google.inject.Binding; /** * This class is an extension of {@link FrameworkMethod} that makes it possible to specify * which {@link Binding} to use for parameters marked with {@literal @}{@link All}. */ public class InjectedFrameworkMethod extends FrameworkMethod { private final List> bindingsToUseForParameters; public InjectedFrameworkMethod(Method method) { super(method); bindingsToUseForParameters = null; } public InjectedFrameworkMethod(Method method, List> bindingsToUseForParameters) { super(method); this.bindingsToUseForParameters = bindingsToUseForParameters; } public List> getBindingsToUseForParameters() { return bindingsToUseForParameters; } } ================================================ FILE: jukito/src/main/java/org/jukito/InjectedStatement.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.internal.Errors; /** * A {@link Statement} invoking a method with parameters by filling-in these * parameters with injected instances. */ class InjectedStatement extends Statement { private final FrameworkMethod method; private final Object test; private final Injector injector; InjectedStatement(FrameworkMethod method, Object test, Injector injector) { this.method = method; this.test = test; this.injector = injector; } @Override public void evaluate() throws Throwable { Method javaMethod = method.getMethod(); Injector methodInjector = injector; UseModules useModules = javaMethod.getAnnotation(UseModules.class); if (useModules != null) { Class[] moduleClasses = useModules.value(); final Module[] modules = new Module[moduleClasses.length]; for (int i = 0; i < modules.length; i++) { modules[i] = moduleClasses[i].newInstance(); } TestModule jukitoModule; if (useModules.autoBindMocks()) { jukitoModule = new JukitoModule() { @Override protected void configureTest() { for (Module m : modules) { install(m); } } }; } else { jukitoModule = new TestModule() { @Override protected void configureTest() { for (Module m : modules) { install(m); } } }; } methodInjector = Guice.createInjector(jukitoModule); } Errors errors = new Errors(javaMethod); List> keys = GuiceUtils.getMethodKeys(javaMethod, errors); errors.throwConfigurationExceptionIfErrorsExist(); Iterator> bindingIter; if (InjectedFrameworkMethod.class.isAssignableFrom(method.getClass())) { bindingIter = ((InjectedFrameworkMethod) method).getBindingsToUseForParameters().iterator(); } else { bindingIter = new ArrayList>().iterator(); } List injectedParameters = new ArrayList(); for (Key key : keys) { if (!All.class.equals(key.getAnnotationType())) { injectedParameters.add(methodInjector.getInstance(key)); } else { if (!bindingIter.hasNext()) { throw new AssertionError("Expected more bindings to fill @All parameters."); } injectedParameters.add(methodInjector.getInstance(bindingIter.next().getKey())); } } method.invokeExplosively(test, injectedParameters.toArray()); } } ================================================ FILE: jukito/src/main/java/org/jukito/JukitoInternal.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.BindingAnnotation; /** * An internal binding annotation used when binding {@link SpyProvider}. * See {@link TestModule#bindSpy(Class)}. */ @BindingAnnotation @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @interface JukitoInternal { } ================================================ FILE: jukito/src/main/java/org/jukito/JukitoModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.jukito.BindingsCollector.BindingInfo; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.inject.ConfigurationException; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.MembersInjector; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.Stage; import com.google.inject.TypeLiteral; import com.google.inject.assistedinject.Assisted; import com.google.inject.internal.Errors; import com.google.inject.internal.ProviderMethod; import com.google.inject.internal.ProviderMethodsModule; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import com.google.inject.spi.InjectionPoint; /** * A guice {@link com.google.inject.Module Module} with a bit of syntactic sugar * to bind within typical test scopes. Depends on mockito. This module * automatically mocks any interface or abstract class dependency for which a * binding is not explicitly provided. Any concrete class for which a binding is * not explicitly provided is bound as a {@link TestScope#SINGLETON}. *

* Depends on Mockito. */ public abstract class JukitoModule extends TestModule { protected List bindingsObserved = Collections.emptyList(); private final Set> forceMock = new HashSet<>(); private final Set> dontForceMock = new HashSet<>(); private final List> keysNeedingTransitiveDependencies = new ArrayList<>(); private final Map, Object> primitiveTypes = new HashMap<>(); public JukitoModule() { primitiveTypes.put(String.class, ""); primitiveTypes.put(Integer.class, 0); primitiveTypes.put(Long.class, 0L); primitiveTypes.put(Boolean.class, false); primitiveTypes.put(Double.class, 0.0); primitiveTypes.put(Float.class, 0.0f); primitiveTypes.put(Short.class, (short) 0); primitiveTypes.put(Character.class, '\0'); primitiveTypes.put(Byte.class, (byte) 0); primitiveTypes.put(Class.class, Object.class); } /** * Attach this {@link JukitoModule} to a list of the bindings that were * observed by a preliminary run of {@link BindingsCollector}. * * @param bindingsObserved The observed bindings. */ public void setBindingsObserved(List bindingsObserved) { this.bindingsObserved = bindingsObserved; } /** * By default, only abstract classes, interfaces and classes annotated with * {@link TestMockSingleton} are automatically mocked. Use {@link #forceMock} * to indicate that all concrete classes derived from the a specific type * will be mocked in {@link TestMockSingleton} scope. * * @param klass The {@link Class} or interface for which all subclasses will be mocked. */ protected void forceMock(Class klass) { forceMock.add(klass); } @Override @SuppressWarnings({"unchecked", "rawtypes"}) public final void configure() { bindScopes(); configureTest(); Set> keysObserved = new HashSet<>(bindingsObserved.size()); Set> keysNeeded = new HashSet<>(bindingsObserved.size()); for (BindingInfo bindingInfo : bindingsObserved) { if (bindingInfo.key != null) { keysObserved.add(bindingInfo.key); } if (bindingInfo.boundKey != null) { keysNeeded.add(bindingInfo.boundKey); } if (bindingInfo.boundInstance != null && bindingInfo.boundInstance instanceof HasDependencies) { HasDependencies hasDependencies = (HasDependencies) bindingInfo.boundInstance; for (Dependency dependency : hasDependencies.getDependencies()) { keysNeeded.add(dependency.getKey()); } } } // registering keys build via @Provides methods in this module in the keysObserved set. ProviderMethodsModule providerMethodsModule = (ProviderMethodsModule) ProviderMethodsModule.forModule(this); List> providerMethodList = providerMethodsModule.getProviderMethods(binder()); for (ProviderMethod providerMethod : providerMethodList) { keysObserved.add(providerMethod.getKey()); } // 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); } // Preempt JIT binding by looking through the test class and any parent class // looking for methods annotated with @Test, @Before, or @After. // Concrete classes bound in this way are bound in @TestSingleton. Class currentClass = testClass; while (currentClass != null) { for (Method method : currentClass.getDeclaredMethods()) { if (method.isAnnotationPresent(Test.class) || method.isAnnotationPresent(Before.class) || method.isAnnotationPresent(After.class)) { Errors errors = new Errors(method); List> keys = GuiceUtils.getMethodKeys(method, errors); for (Key key : keys) { // Skip keys annotated with @All if (!All.class.equals(key.getAnnotationType())) { Key keyNeeded = GuiceUtils.ensureProvidedKey(key, errors); addNeededKey(keysObserved, keysNeeded, keyNeeded, true); } } errors.throwConfigurationExceptionIfErrorsExist(); } } currentClass = currentClass.getSuperclass(); } // Preempt JIT binding by looking through the test class looking for // fields and methods annotated with @Inject. // Concrete classes bound in this way are bound in @TestSingleton. if (testClass != null) { Set injectionPoints = InjectionPoint.forInstanceMethodsAndFields(testClass); for (InjectionPoint injectionPoint : injectionPoints) { Errors errors = new Errors(injectionPoint); List> dependencies = injectionPoint.getDependencies(); for (Dependency dependency : dependencies) { Key keyNeeded = GuiceUtils.ensureProvidedKey(dependency.getKey(), errors); addNeededKey(keysObserved, keysNeeded, keyNeeded, true); } errors.throwConfigurationExceptionIfErrorsExist(); } } // Recursively add the dependencies of all the bindings observed. Warning, we can't use for each here // since it would result into concurrency issues. for (int i = 0; i < keysNeedingTransitiveDependencies.size(); ++i) { addDependencies(keysNeedingTransitiveDependencies.get(i), keysObserved, keysNeeded); } // Bind all keys needed but not observed as mocks. for (Key key : keysNeeded) { Class rawType = key.getTypeLiteral().getRawType(); if (!keysObserved.contains(key) && !isCoreGuiceType(rawType) && !isAssistedInjection(key)) { Object primitiveInstance = getDummyInstanceOfPrimitiveType(rawType); if (primitiveInstance == null) { if (rawType != Provider.class && !isInnerClass(rawType)) { bind(key).toProvider(new MockProvider(rawType)).in(TestScope.SINGLETON); } } else { bindKeyToInstance(key, primitiveInstance); } } } } private boolean isInnerClass(Class rawType) { return rawType.isMemberClass() && !Modifier.isStatic(rawType.getModifiers()); } @SuppressWarnings("unchecked") private void bindKeyToInstance(Key key, Object primitiveInstance) { bind(key).toInstance((T) primitiveInstance); } private void addNeededKey(Set> keysObserved, Set> keysNeeded, Key keyNeeded, boolean asTestSingleton) { keysNeeded.add(keyNeeded); bindIfConcrete(keysObserved, keyNeeded, asTestSingleton); } private void bindIfConcrete(Set> keysObserved, Key key, boolean asTestSingleton) { TypeLiteral typeToBind = key.getTypeLiteral(); Class rawType = typeToBind.getRawType(); if (!keysObserved.contains(key) && canBeInjected(typeToBind) && !shouldForceMock(rawType) && !isAssistedInjection(key)) { // If an @Singleton annotation is present, force the bind as TestSingleton if (asTestSingleton || rawType.getAnnotation(Singleton.class) != null) { bind(key).in(TestScope.SINGLETON); } else { bind(key); } keysObserved.add(key); keysNeedingTransitiveDependencies.add(key); } } private boolean canBeInjected(TypeLiteral type) { Class rawType = type.getRawType(); if (isPrimitive(rawType) || isCoreGuiceType(rawType) || !isInstantiable(rawType)) { return false; } try { InjectionPoint.forConstructorOf(type); return true; } catch (ConfigurationException e) { return false; } } private boolean isAssistedInjection(Key key) { return key.getAnnotationType() != null && Assisted.class.isAssignableFrom(key.getAnnotationType()); } private boolean shouldForceMock(Class klass) { if (dontForceMock.contains(klass)) { return false; } if (forceMock.contains(klass)) { return true; } // The forceMock set contains all the base classes the user wants // to force mock, check id the specified klass is a subclass of one of // these. // Update forceMock or dontForceMock based on the result to speed-up // future look-ups. boolean result = false; for (Class classToMock : forceMock) { if (classToMock.isAssignableFrom(klass)) { result = true; break; } } if (result) { forceMock.add(klass); } else { dontForceMock.add(klass); } return result; } private boolean isInstantiable(Class klass) { return !klass.isInterface() && !Modifier.isAbstract(klass.getModifiers()); } private boolean isPrimitive(Class klass) { return getDummyInstanceOfPrimitiveType(klass) != null; } private Object getDummyInstanceOfPrimitiveType(Class klass) { Object instance = primitiveTypes.get(klass); if (instance == null && Enum.class.isAssignableFrom(klass)) { // Safe to ignore exception, Guice will fail with a reasonable error // if the Enum is empty. try { instance = ((Object[]) klass.getMethod("values").invoke(null))[0]; } catch (Exception ignored) { } } return instance; } private boolean isCoreGuiceType(Class klass) { return TypeLiteral.class.isAssignableFrom(klass) || Injector.class.isAssignableFrom(klass) || Logger.class.isAssignableFrom(klass) || Stage.class.isAssignableFrom(klass) || MembersInjector.class.isAssignableFrom(klass); } private void addDependencies(Key key, Set> keysObserved, Set> keysNeeded) { TypeLiteral type = key.getTypeLiteral(); if (!canBeInjected(type)) { return; } addInjectionPointDependencies(InjectionPoint.forConstructorOf(type), keysObserved, keysNeeded); Set methodsAndFieldsInjectionPoints = InjectionPoint.forInstanceMethodsAndFields(type); for (InjectionPoint injectionPoint : methodsAndFieldsInjectionPoints) { addInjectionPointDependencies(injectionPoint, keysObserved, keysNeeded); } } private void addInjectionPointDependencies(InjectionPoint injectionPoint, Set> keysObserved, Set> keysNeeded) { // Do not consider dependencies coming from optional injections if (injectionPoint.isOptional()) { return; } for (Dependency dependency : injectionPoint.getDependencies()) { Key key = dependency.getKey(); addKeyDependency(key, keysObserved, keysNeeded); } } private void addKeyDependency(Key key, Set> keysObserved, Set> keysNeeded) { Key newKey = key; if (Provider.class.equals(key.getTypeLiteral().getRawType())) { Type providedType = ( (ParameterizedType) key.getTypeLiteral().getType()).getActualTypeArguments()[0]; if (key.getAnnotation() != null) { newKey = Key.get(providedType, key.getAnnotation()); } else if (key.getAnnotationType() != null) { newKey = Key.get(providedType, key.getAnnotationType()); } else { newKey = Key.get(providedType); } } addNeededKey(keysObserved, keysNeeded, newKey, true); } /** * Override and return the {@link Writer} you want to use to report the tree of test objects,and whether they * were mocked, spied, automatically instantiated, or explicitly bound. Mostly useful for * debugging. * * @return The {@link Writer}, if {@code null} no report will be output. */ public Writer getReportWriter() { return null; } /** * Outputs the report, see {@link #setReportWriter(Writer)}. Will not output anything if the * {@code reportWriter} is {@code null}. Do not call directly, it will be called by * {@link JukitoRunner}. To obtain a report, override {@link #getReportWriter()}. */ public void printReport(List allBindings) { Writer reportWriter = getReportWriter(); if (reportWriter == null) { return; } try { reportWriter.append("*** EXPLICIT BINDINGS ***\n"); Set> reportedKeys = outputBindings(reportWriter, bindingsObserved, Collections.>emptySet()); reportWriter.append('\n'); reportWriter.append("*** AUTOMATIC BINDINGS ***\n"); outputBindings(reportWriter, allBindings, reportedKeys); reportWriter.append('\n'); } catch (IOException e) { e.printStackTrace(); } } /** * @param reportWriter The {@link Writer} to use to output the report. * @param bindings The bindings to report. * @param keysToSkip The keys that should not be reported. * @return All the keys that were reported. * @throws IOException If something goes wrong when writing. */ private Set> outputBindings(Writer reportWriter, List bindings, Set> keysToSkip) throws IOException { Set> reportedKeys = new HashSet<>(bindings.size()); for (BindingInfo bindingInfo : bindings) { if (keysToSkip.contains(bindingInfo.key)) { continue; } reportedKeys.add(bindingInfo.key); reportWriter.append(" "); reportWriter.append(bindingInfo.key.toString()); reportWriter.append(" --> "); if (bindingInfo.boundKey != null) { if (bindingInfo.key == bindingInfo.boundKey) { reportWriter.append("Bound directly"); } else { reportWriter.append(bindingInfo.boundKey.toString()); } } else if (bindingInfo.boundInstance != null) { reportWriter.append("Instance of ").append(bindingInfo.boundInstance.getClass().getCanonicalName()); } else { reportWriter.append("NOTHING!?"); } reportWriter.append(" ### "); if (bindingInfo.scope == null) { reportWriter.append("No scope"); } else { reportWriter.append("In scope "); reportWriter.append(bindingInfo.scope); } reportWriter.append('\n'); } return reportedKeys; } } ================================================ FILE: jukito/src/main/java/org/jukito/JukitoRunner.java ================================================ /* * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.Scope; import com.google.inject.TypeLiteral; import com.google.inject.internal.Errors; import com.google.inject.spi.DefaultBindingScopingVisitor; /* * This class implements the mockito runner but allows Guice dependency * injection. To setup the guice environment, the test class can have an inner * static class deriving from {@link TestModule}. This last class will let you bind * {@link TestSingleton} and {@link TestEagerSingleton} and the runner will make sure these * singletons are reset at every invocation of a test case. * * * Most of the code here is inspired from: http://cowwoc.blogspot.com/2008/10/integrating-google-guice-into-junit4. * html * * Depends on Mockito. */ public class JukitoRunner extends BlockJUnit4ClassRunner { private Injector injector; public JukitoRunner(Class klass) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException { super(klass); ensureInjector(); } public JukitoRunner(Class klass, Injector injector) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException { // refactor needed here cos ensureInjector is run without reason here. super(klass); this.injector = injector; } /** * Creates an injector from a test module. * Override this to use something like Netflix Governator. * * @param testModule the test module * @return a newly created injector */ protected Injector createInjector(TestModule testModule) { return Guice.createInjector(testModule); } private void ensureInjector() throws InstantiationException, IllegalAccessException { if (injector != null) { return; } Class testClass = getTestClass().getJavaClass(); TestModule testModule = getTestModule(testClass); testModule.setTestClass(testClass); JukitoModule jukitoModule = null; // Only non-null if it's a JukitoModule if (testModule instanceof JukitoModule) { jukitoModule = (JukitoModule) testModule; // Create a module just for the purpose of collecting bindings TestModule testModuleForCollection = getTestModule(testClass); BindingsCollector collector = new BindingsCollector(testModuleForCollection); collector.collectBindings(); jukitoModule.setBindingsObserved(collector.getBindingsObserved()); } injector = this.createInjector(testModule); if (jukitoModule != null && jukitoModule.getReportWriter() != null) { // An output report is desired BindingsCollector collector = new BindingsCollector(jukitoModule); collector.collectBindings(); jukitoModule.printReport(collector.getBindingsObserved()); } } private TestModule getTestModule(Class testClass) throws InstantiationException, IllegalAccessException { Set> useModuleClasses = getUseModuleClasses(testClass); boolean autoBindMocks = getAutoBindMocksValue(testClass); if (!useModuleClasses.isEmpty()) { return createJukitoModule(useModuleClasses, autoBindMocks); } TestModule testModule = getInnerClassModule(testClass); if (testModule != null) { return testModule; } if (autoBindMocks) { return new JukitoModule() { @Override protected void configureTest() { } }; } else { return new TestModule() { @Override protected void configureTest() { } }; } } /** * Gets Guice modules registered with {@link UseModules} from test class and all super classes. * * @param testClass the test class running * @return set of Guice modules */ private Set> getUseModuleClasses(Class testClass) { Class currentClass = testClass; Set> modules = new HashSet<>(); while (currentClass != null) { UseModules useModules = currentClass.getAnnotation(UseModules.class); if (useModules != null) { Collections.addAll(modules, useModules.value()); } currentClass = currentClass.getSuperclass(); } return modules; } private TestModule getInnerClassModule(Class testClass) throws InstantiationException, IllegalAccessException { Class currentClass = testClass; while (currentClass != null) { for (Class innerClass : currentClass.getDeclaredClasses()) { if (TestModule.class.isAssignableFrom(innerClass)) { return (TestModule) innerClass.newInstance(); } } currentClass = currentClass.getSuperclass(); } return null; } private boolean getAutoBindMocksValue(Class testClass) { boolean autoBindMocks = true; Class currentClass = testClass; while (currentClass != null) { UseModules useModules = currentClass.getAnnotation(UseModules.class); if (useModules != null) { autoBindMocks = useModules.autoBindMocks(); break; } currentClass = currentClass.getSuperclass(); } return autoBindMocks; } private TestModule createJukitoModule(final Iterable> moduleClasses, boolean autoBindMocks) { if (autoBindMocks) { return new JukitoModule() { @Override protected void configureTest() { for (Class mClass : moduleClasses) { try { install(mClass.newInstance()); } catch (Exception e) { throw new RuntimeException(e); } } } }; } else { return new TestModule() { @Override protected void configureTest() { for (Class mClass : moduleClasses) { try { install(mClass.newInstance()); } catch (Exception e) { throw new RuntimeException(e); } } } }; } } @Override public void run(RunNotifier notifier) { // add listener that validates framework usage at the end of each test notifier.addListener(new MockitoUsageValidator(notifier)); super.run(notifier); } @Override protected Object createTest() throws Exception { TestScope.clear(); instantiateEagerTestSingletons(); return injector.getInstance(getTestClass().getJavaClass()); } @Override protected Statement methodInvoker(FrameworkMethod method, Object test) { return new InjectedStatement(method, test, injector); } @Override protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) { try { ensureInjector(); } catch (Exception e) { throw new RuntimeException(e); } List befores = getTestClass().getAnnotatedMethods( Before.class); return befores.isEmpty() ? statement : new InjectedBeforeStatements(statement, befores, target, injector); } @Override protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) { try { ensureInjector(); } catch (Exception e) { throw new RuntimeException(e); } List afters = getTestClass().getAnnotatedMethods( After.class); return afters.isEmpty() ? statement : new InjectedAfterStatements(statement, afters, target, injector); } @Override protected List computeTestMethods() { try { ensureInjector(); } catch (Exception e) { throw new RuntimeException(e); } List testMethods = getTestClass().getAnnotatedMethods(Test.class); List result = new ArrayList<>(testMethods.size()); for (FrameworkMethod method : testMethods) { Method javaMethod = method.getMethod(); Errors errors = new Errors(javaMethod); List> keys = GuiceUtils.getMethodKeys(javaMethod, errors); errors.throwConfigurationExceptionIfErrorsExist(); List>> bindingsToUseForParameters = new ArrayList<>(); for (Key key : keys) { if (All.class.equals(key.getAnnotationType())) { All allAnnotation = (All) key.getAnnotation(); TypeLiteral typeLiteral = key.getTypeLiteral(); List> bindings = getBindingsForParameterWithAllAnnotation(allAnnotation, typeLiteral); bindingsToUseForParameters.add(bindings); } } // Add an injected method for every combination of binding addAllBindingAssignations(bindingsToUseForParameters, 0, new ArrayList>(bindingsToUseForParameters.size()), javaMethod, result); } return result; } @Override protected String testName(FrameworkMethod method) { org.jukito.Description annotation = method.getMethod().getAnnotation(org.jukito.Description.class); if (annotation != null) { return annotation.value(); } else { return super.testName(method); } } /** * Computes a list of all bindings which match a {@link All} annotation. * * @param allAnnotation the annotation to match * @param typeLiteral the type of the bindings. * @return the computed list. */ private List> getBindingsForParameterWithAllAnnotation(All allAnnotation, TypeLiteral typeLiteral) { List> result = new ArrayList<>(); String bindingName = allAnnotation.value(); if (All.DEFAULT.equals(bindingName)) { // If the annotation is with the default name bind all bindings result.addAll(injector.findBindingsByType(typeLiteral)); } else { // Else bind only those bindings which have a key with the same name for (Binding binding : injector.findBindingsByType(typeLiteral)) { if (NamedUniqueAnnotations.matches(bindingName, binding.getKey().getAnnotation())) { result.add(binding); } } } return result; } /** * This method looks at all possible way to assign the bindings in * {@code bindingsToUseForParameters}, starting at index {@code index}. * If {@code index} is larger than the number of elements in {@code bindingsToUseForParameters} * then the {@code currentAssignation} with {@javaMethod} is added to {@code result}. * * @param result * @param javaMethod * @param bindingsToUseForParameters * @param index * @param currentAssignation */ private void addAllBindingAssignations( List>> bindingsToUseForParameters, int index, List> currentAssignation, Method javaMethod, List result) { if (index >= bindingsToUseForParameters.size()) { List> assignation = new ArrayList<>(currentAssignation.size()); assignation.addAll(currentAssignation); result.add(new InjectedFrameworkMethod(javaMethod, assignation)); return; } for (Binding binding : bindingsToUseForParameters.get(index)) { if (binding.getKey().getAnnotation() == null) { // As TestModule.bindMany() annotates the bindings, the un-annotated bindings are typically unwanted // mocks automatically bound by Jukito. continue; } currentAssignation.add(binding); if (currentAssignation.size() != index + 1) { throw new AssertionError("Size of currentAssignation list is wrong."); } addAllBindingAssignations(bindingsToUseForParameters, index + 1, currentAssignation, javaMethod, result); currentAssignation.remove(index); } } private void instantiateEagerTestSingletons() { DefaultBindingScopingVisitor isEagerTestScopeSingleton = new DefaultBindingScopingVisitor() { public Boolean visitScope(Scope scope) { return scope == TestScope.EAGER_SINGLETON; } }; for (Binding binding : injector.getBindings().values()) { boolean instantiate = false; if (binding != null) { Boolean result = binding.acceptScopingVisitor(isEagerTestScopeSingleton); if (result != null && result) { instantiate = true; } } if (instantiate) { binding.getProvider().get(); } } } /** * Adds to {@code errors} for each method annotated with {@code @Test}, * {@code @Before}, or {@code @After} that is not a public, void instance * method with no arguments. */ @Override protected void validateInstanceMethods(List errors) { validatePublicVoidMethods(After.class, false, errors); validatePublicVoidMethods(Before.class, false, errors); validateTestMethods(errors); if (computeTestMethods().size() == 0) { errors.add(new Exception("No runnable methods")); } } /** * Adds to {@code errors} for each method annotated with {@code @Test}that * is not a public, void instance method with no arguments. */ @Override protected void validateTestMethods(List errors) { validatePublicVoidMethods(Test.class, false, errors); } /** * Adds to {@code errors} if any method in this class is annotated with * the provided {@code annotation}, but: *

    *
  • is not public, or *
  • returns something other than void, or *
  • is static (given {@code isStatic is false}), or *
  • is not static (given {@code isStatic is true}). */ private void validatePublicVoidMethods(Class annotation, boolean isStatic, List errors) { List methods = getTestClass().getAnnotatedMethods(annotation); for (FrameworkMethod eachTestMethod : methods) { eachTestMethod.validatePublicVoid(isStatic, errors); } } /** * Access the Guice injector. * * @return The Guice {@link Injector}. */ protected Injector getInjector() { return injector; } } ================================================ FILE: jukito/src/main/java/org/jukito/MockProvider.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import com.google.inject.Provider; import static org.mockito.Mockito.mock; /** * For use in test cases where an {@link Provider} is required to provide an * object and the test case needs to provide a mock of the object. *

    * A new object is returned each the the provider is invoked, unless the object * is bound as a {@link TestScope#SINGLETON} or {@link TestScope#EAGER_SINGLETON}. *

    * Depends on Mockito. * * @param The class to provide. */ public class MockProvider implements Provider { private final Class classToProvide; /** * Construct a {@link Provider} that will return mocked objects of the specified types. * * @param classToProvide The {@link Class} of the mock object to provide. */ public MockProvider(Class classToProvide) { this.classToProvide = classToProvide; } @Override public T get() { return mock(classToProvide); } } ================================================ FILE: jukito/src/main/java/org/jukito/MockitoUsageValidator.java ================================================ /* * Copyright 2017 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; import org.junit.runner.notification.RunNotifier; import org.mockito.Mockito; public class MockitoUsageValidator extends RunListener { private final RunNotifier notifier; public MockitoUsageValidator(RunNotifier notifier) { this.notifier = notifier; } @Override public void testFinished(org.junit.runner.Description description) throws Exception { super.testFinished(description); try { Mockito.validateMockitoUsage(); } catch (Throwable t) { notifier.fireTestFailure(new Failure(description, t)); } } } ================================================ FILE: jukito/src/main/java/org/jukito/NamedUniqueAnnotations.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.util.concurrent.atomic.AtomicInteger; import com.google.inject.BindingAnnotation; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Factory for unique annotations with a name. Based on {@link com.google.inject.internal.UniqueAnnotations}. */ class NamedUniqueAnnotations { private static final AtomicInteger nextUniqueValue = new AtomicInteger(1); /** * Returns if a NamedUniqueAnnotations matches a binding name. * * @param bindingName the name to match. * @param annotation the annotation to match the name to. * @return if the annotation matches the bindingName. */ public static boolean matches(String bindingName, java.lang.annotation.Annotation annotation) { if (annotation instanceof Internal) { return ((Internal) annotation).name().equals(bindingName); } return false; } /** * Returns an annotation instance that is not equal to any other annotation * instances, for use in creating distinct {@link com.google.inject.Key}s. * * @param name name to group multiple annotations. Each annotation is still unique even if it belongs to a group. */ public static Annotation create(String name) { int unique = nextUniqueValue.getAndIncrement(); String nonNullName = name == null ? All.DEFAULT : name; return new InternalImpl(unique, nonNullName); } @Retention(RUNTIME) @BindingAnnotation private @interface Internal { String name(); int value(); } private static class InternalImpl implements Internal { private final int value; private final String name; InternalImpl(int value, String name) { this.value = value; this.name = name; } public int value() { return value; } public String name() { return name; } public Class annotationType() { return Internal.class; } @Override public String toString() { return "@" + Internal.class.getName() + "(name=" + name + ", value=" + value + ")"; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o instanceof Internal) { Internal other = (Internal) o; return value() == other.value() && name().equals(other.name()); } return false; } @Override public int hashCode() { return (127 * name.hashCode()) ^ value; } } } ================================================ FILE: jukito/src/main/java/org/jukito/SpyImmutableInstanceProvider.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.mockito.Mockito; import com.google.inject.Provider; /** * For use in classes where you want to create a spied instance, as in * {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(T))}, * except the instance is a spy. *

    * A new spy is returned each time this {@link Provider} is invoked, wrapping the * exact same instance class. *

    * Important: Spied object needs to be Immutable */ class SpyImmutableInstanceProvider implements Provider { private final T instance; /** * Create a new {@link Provider} instance for use in creating spies of * concrete instances. *

    * This instance should be immutable; if it is not, you risk polluting your tests as the underlying instance is the * same (even though it uses a different spy wrapper). * * @param instance The instance to be returned. */ SpyImmutableInstanceProvider(T instance) { this.instance = instance; } /** * Create a new spy of your bound instance. */ @Override public T get() { return Mockito.spy(instance); } } ================================================ FILE: jukito/src/main/java/org/jukito/SpyProvider.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.Collections; import java.util.Set; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import static org.mockito.Mockito.spy; /** * For use in test cases where an {@link Provider} is required to provide an * object and the test case needs to provide a spy of the object. *

    * A new object is returned each the the provider is invoked, unless the object * is bound as a {@link TestScope#SINGLETON} or {@link TestScope#EAGER_SINGLETON}. *

    * Depends on Mockito. * * @param The class to provide. */ class SpyProvider implements Provider, HasDependencies { private final Provider rawProvider; private final Set> dependencies; /** * Construct a {@link Provider} that will return spied instances of objects * of the specified types. You should not call this directly, instead use * {@link TestModule#bindSpy(Class)} or {@link TestModule#bindSpy(com.google.inject.TypeLiteral)}. * * @param rawProvider The test class, running with {@link JukitoRunner}. * @param relayingKey The key of the binding used to relay to the real class. This should usually be the key of a * {code toConstructor} binding. Internally, Jukito uses the {@link JukitoInternal} annotation to * distinguish this binding. */ SpyProvider(Provider rawProvider, Key relayingKey) { this.rawProvider = rawProvider; dependencies = Collections.>singleton(Dependency.get(relayingKey)); } @Override public T get() { return spy(rawProvider.get()); } @Override public Set> getDependencies() { return dependencies; } } ================================================ FILE: jukito/src/main/java/org/jukito/TestEagerSingleton.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.ScopeAnnotation; /** * This annotation can be used on any classes that should be bound * within the {@link TestScope#EAGER_SINGLETON} scope. It is meant to be * used on inner static classes of the test class or its parents * and shouldn't be used on top-level classes. */ @ScopeAnnotation @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface TestEagerSingleton { } ================================================ FILE: jukito/src/main/java/org/jukito/TestMockSingleton.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation can be used on any classes that should be bound as * a mock within the {@link TestScope#SINGLETON} scope. It is meant to be * used on inner static classes of the test class or its parents * and shouldn't be used on top-level classes. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TestMockSingleton { } ================================================ FILE: jukito/src/main/java/org/jukito/TestModule.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.reflect.Constructor; import com.google.inject.AbstractModule; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.binder.LinkedBindingBuilder; import com.google.inject.binder.ScopedBindingBuilder; import com.google.inject.name.Names; import com.google.inject.spi.InjectionPoint; /** * A guice {@link com.google.inject.Module Module} with a bit of syntactic sugar to bind within * typical test scopes. Depends on mockito. *

    * Depends on Mockito. */ public abstract class TestModule extends AbstractModule { protected Class testClass; /** * Attach the {@link TestModule} to a given test class. * * @param testClass The test class to attach to this {@link TestModule}. */ public void setTestClass(Class testClass) { this.testClass = testClass; } @Override public void configure() { bindScopes(); configureTest(); } protected void bindScopes() { bindScope(TestSingleton.class, TestScope.SINGLETON); bindScope(TestEagerSingleton.class, TestScope.EAGER_SINGLETON); } /** * Configures a test {@link com.google.inject.Module Module} via the exposed methods. */ protected abstract void configureTest(); /** * Binds an interface to a mocked version of itself. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindMock(Class klass) { return bindNewMockProvider(Key.get(klass)); } /** * Binds an interface annotated with a {@link com.google.inject.name.Named @Named} to a * mocked version of itself. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind, a parameterized type * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindMock( TypeLiteral typeLiteral) { return bindNewMockProvider(Key.get(typeLiteral)); } /** * Binds a concrete object type so that spies of instances are returned * instead of instances themselves. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindSpy(Class klass) { return bindNewSpyProvider(Key.get(klass)); } /** * Binds a concrete object type so that spies of instances are returned * instead of instances themselves. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind, a parameterized type * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindSpy( TypeLiteral typeLiteral) { return bindNewSpyProvider(Key.get(typeLiteral)); } /** * Binds a concrete instance so that spies of this instance are returned * instead of the object itself. Each spy is an independent spy but the * underlying instance will be the same, so if the object is mutable, * your tests can be polluted! *

    * You will usually want to bind this in the {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @param instance The instance to bind this class to. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindSpy(Class klass, T instance) { return bindNewSpyImmutableInstanceProvider(Key.get(klass), instance); } /** * Binds a concrete instance so that spies of this instance are returned * instead of the object itself. Each spy is an independent spy but the * underlying instance will be the same, so if the object is mutable, * your tests can be polluted! *

    * You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind, a parameterized type * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @param instance The instance to bind this class to. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindSpy( TypeLiteral typeLiteral, T instance) { return bindNewSpyImmutableInstanceProvider(Key.get(typeLiteral), instance); } /** * Binds an interface annotated with a {@link com.google.inject.name.Named @Named} to a * mocked version of itself. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedMock(Class klass, String name) { return bindNewMockProvider(Key.get(klass, Names.named(name))); } /** * Binds an interface annotated with a {@link com.google.inject.name.Named @Named} to a * mocked version of itself. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedMock(TypeLiteral typeLiteral, String name) { return bindNewMockProvider(Key.get(typeLiteral, Names.named(name))); } /** * Binds a concrete object type annotated with a * {@link com.google.inject.name.Named @Named} so that spies of instances are returned * instead of instances themselves. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedSpy(Class klass, String name) { return bindNewSpyProvider(Key.get(klass, Names.named(name))); } /** * Binds a concrete object type annotated with a * {@link com.google.inject.name.Named @Named} so that spies of instances are returned * instead of instances themselves. You will usually want to bind this in the * {@link TestSingleton} scope. * * @param The type of the interface to bind * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedSpy(TypeLiteral typeLiteral, String name) { return bindNewSpyProvider(Key.get(typeLiteral, Names.named(name))); } /** * Binds a concrete instance annotated with {@link com.google.inject.name.Named @Named} so that spies of this * instance are returned instead of the object itself. Each spy is an independent spy but the underlying instance * will be the same, so if the object is mutable, your tests can be polluted! *

    * You will usually want to bind this in the {@link TestSingleton} scope. * * @param The type of the interface to bind * @param klass The class to bind * @param instance The instance to bind this class to. * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedSpy(Class klass, T instance, String name) { return bindNewSpyImmutableInstanceProvider(Key.get(klass, Names.named(name)), instance); } /** * Binds a concrete instance annotated with {@link com.google.inject.name.Named @Named} so that spies of this * instance are returned instead of the object itself. Each spy is an independent spy but the underlying instance * will be the same, so if the object is mutable, your tests can be polluted! *

    * You will usually want to bind this in the {@link TestSingleton} scope. * * @param The type of the interface to bind * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @param instance The instance to bind this class to. * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected ScopedBindingBuilder bindNamedSpy(TypeLiteral typeLiteral, T instance, String name) { return bindNewSpyImmutableInstanceProvider(Key.get(typeLiteral, Names.named(name)), instance); } @SuppressWarnings("unchecked") private ScopedBindingBuilder bindNewMockProvider(Key key) { return bind(key).toProvider( new MockProvider((Class) key.getTypeLiteral().getRawType())); } @SuppressWarnings("unchecked") private ScopedBindingBuilder bindNewSpyProvider(Key key) { TypeLiteral type = key.getTypeLiteral(); InjectionPoint constructorInjectionPoint = InjectionPoint.forConstructorOf(type); Key relayingKey = Key.get(type, JukitoInternal.class); bind(relayingKey).toConstructor((Constructor) constructorInjectionPoint.getMember()); return bind(key).toProvider(new SpyProvider(getProvider(relayingKey), relayingKey)); } private ScopedBindingBuilder bindNewSpyImmutableInstanceProvider(Key key, T instance) { return bind(key).toProvider(new SpyImmutableInstanceProvider(instance)); } /** * This method binds many different instances to the same class or interface. Use this only * if the instances are totally stateless. That is, they are immutable and have * no mutable dependencies (e.g. a {@link String} or a simple POJO). For more * complex classes use {@link #bindMany}. *

    * The specified {@link Class} will be bound to all the different instances, each * binding using a different unique annotation. *

    * This method is useful when combined with the {@literal @}{@link All} annotation. * * @param clazz The {@link Class} to which the instances will be bound. * @param instances All the instances to bind. * @see {@link All} */ protected void bindManyInstances(Class clazz, V... instances) { bindManyNamedInstances(clazz, All.DEFAULT, instances); } /** * This method binds many different instances to the same class or interface. Use this only * if the instances are totally stateless. That is, they are immutable and have * no mutable dependencies (e.g. a {@link String} or a simple POJO). For more * complex classes use {@link #bindMany}. *

    * The specified {@link Class} will be bound to all the different instances, each * binding using a different unique but named annotation. *

    * This method is useful when combined with the {@literal @}{@link All} annotation with * a name parameter. * * @param clazz The {@link Class} to which the instances will be bound. * @param name The name to which to bind the instances. * @param instances All the instances to bind. * @see {@link All} */ protected void bindManyNamedInstances(Class clazz, String name, V... instances) { for (V instance : instances) { bind(clazz).annotatedWith(NamedUniqueAnnotations.create(name)).toInstance(instance); } } /** * This method binds many different instances to the same type literal. Use this only * if the instances are totally stateless. That is, they are immutable and have * no mutable dependencies (e.g. a {@link String} or a simple POJO). For more * complex classes use {@link #bindMany}. *

    * The specified {@link TypeLiteral} will be bound to all the different instances, each * binding using a different unique annotation. *

    * This method is useful when combined with the {@literal @}{@link All} annotation. * * @param type The {@link TypeLiteral} to which the instances will be bound. * @param instances All the instances to bind. * @see {@link All} */ protected void bindManyInstances(TypeLiteral type, V... instances) { bindManyNamedInstances(type, All.DEFAULT, instances); } /** * This method binds many different instances to the same class or interface. Use this only * if the instances are totally stateless. That is, they are immutable and have * no mutable dependencies (e.g. a {@link String} or a simple POJO). For more * complex classes use {@link #bindMany}. *

    * The specified {@link Class} will be bound to all the different instances, each * binding using a different unique but named annotation. *

    * This method is useful when combined with the {@literal @}{@link All} annotation with * a name. * * @param type The {@link Class} to which the instances will be bound. * @param name The name to which to bind the instances. * @param instances All the instances to bind. * @see {@link All} */ protected void bindManyNamedInstances(TypeLiteral type, String name, V... instances) { for (V instance : instances) { bind(type).annotatedWith(NamedUniqueAnnotations.create(name)).toInstance(instance); } } /** * This method binds many different classes to the same interface. All the * classes will be bound within the {@link TestScope#SINGLETON} scope. *

    * This method is useful when combined with the {@literal @}{@link All} annotation. * * @param clazz The {@link Class} to which the instances will be bound. * @param boundClasses All the classes to bind. * @see {@link All} */ protected void bindMany(Class clazz, Class... boundClasses) { bindManyNamed(clazz, All.DEFAULT, boundClasses); } /** * This method binds many different type literals to the same type literal. All the * classes will be bound within the {@link TestScope#SINGLETON} scope. *

    * This method is useful when combined with the {@literal @}{@link All} annotation with * a name. * * @param clazz The {@link Class} to which the instances will be bound. * @param name The name to which to bind the instances. * @param boundClasses All the types to bind. * @see {@link All} */ protected void bindManyNamed(Class clazz, String name, Class... boundClasses) { for (Class boundClass : boundClasses) { bind(clazz).annotatedWith(NamedUniqueAnnotations.create(name)).to(boundClass).in(TestScope.SINGLETON); } } /** * This method binds many different type literals to the same type literal. All the * classes will be bound within the {@link TestScope#SINGLETON} scope. *

    * This method is useful when combined with the {@literal @}{@link All} annotation. * * @param type The {@link Class} to which the instances will be bound. * @param boundTypes All the types to bind. * @see {@link All} */ protected void bindMany(TypeLiteral type, TypeLiteral... boundTypes) { bindManyNamed(type, All.DEFAULT, boundTypes); } /** * This method binds many different type literals to the same type literal. All the * classes will be bound within the {@link TestScope#SINGLETON} scope. *

    * This method is useful when combined with the {@literal @}{@link All} annotation with * a name. * * @param type The {@link Class} to which the instances will be bound. * @param name The name to which to bind the instances. * @param boundTypes All the types to bind. * @see {@link All} */ protected void bindManyNamed(TypeLiteral type, String name, TypeLiteral... boundTypes) { for (TypeLiteral boundType : boundTypes) { bind(type).annotatedWith(NamedUniqueAnnotations.create(name)).to(boundType).in(TestScope.SINGLETON); } } /** * Binds an interface annotated with a {@link com.google.inject.name.Named @Named}. * * @param The type of the interface to bind * @param klass The class to bind * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected LinkedBindingBuilder bindNamed(Class klass, String name) { return bind(klass).annotatedWith(Names.named(name)); } /** * Binds an interface annotated with a {@link com.google.inject.name.Named @Named}. * * @param The type of the interface to bind * @param typeLiteral The {@link TypeLiteral} corresponding to the parameterized type to bind. * @param name The name used with the {@link com.google.inject.name.Named @Named} annotation. * @return A {@link ScopedBindingBuilder}. */ protected LinkedBindingBuilder bindNamed(TypeLiteral typeLiteral, String name) { return bind(typeLiteral).annotatedWith(Names.named(name)); } } ================================================ FILE: jukito/src/main/java/org/jukito/TestScope.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.HashMap; import java.util.Map; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.Scope; /** * Container of the {@link #SINGLETON} and {@link #EAGER_SINGLETON} scopes for * test cases running with the {@link JukitoRunner}. Depends on mockito. *

    * Depends on Mockito. */ public class TestScope { private static class Singleton implements Scope { private final String simpleName; private final Map, Object> backingMap = new HashMap, Object>(); private Singleton(String simpleName) { this.simpleName = simpleName; } public void clear() { backingMap.clear(); } @Override public Provider scope(final Key key, final Provider unscoped) { return new Provider() { @SuppressWarnings("unchecked") public T get() { Object o = backingMap.get(key); if (o == null) { o = unscoped.get(); backingMap.put(key, o); } return (T) o; } }; } public String toString() { return simpleName; } } /** * Test-scoped singletons are typically used in test cases for objects that * correspond to singletons in the application. Your JUnit test case must use * {@link JukitoRunner} on its {@code @RunWith} annotation so that * test-scoped singletons are reset before every test case. *

    * If you want your singleton to be instantiated automatically with each new * test, use {@link #EAGER_SINGLETON}. */ public static final Singleton SINGLETON = new Singleton("TestSingleton"); /** * Eager test-scoped singleton are similar to test-scoped {@link #SINGLETON} * but they get instantiated automatically with each new test. */ public static final Singleton EAGER_SINGLETON = new Singleton("EagerTestSingleton"); /** * Clears all the instances of test-scoped singletons. After this method is * called, any "singleton" bound to this scope that had already been created * will be created again next time it gets injected. */ public static void clear() { SINGLETON.clear(); EAGER_SINGLETON.clear(); } } ================================================ FILE: jukito/src/main/java/org/jukito/TestSingleton.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.ScopeAnnotation; /** * This annotation can be used on any classes that should be bound * within the {@link TestScope#SINGLETON} scope. It is meant to be * used on inner static classes ofx the test class or its parents * and shouldn't be used on top-level classes. */ @ScopeAnnotation @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface TestSingleton { } ================================================ FILE: jukito/src/main/java/org/jukito/UseModules.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.google.inject.Module; /** * This annotation can be used on a test class together with * {@code @RunWith(JukitoRunner.class)} to use the bindings contained * in the specified modules for the test. *

    * Example: *

     * {@literal @}RunWith(JukitoRunner.class)
     * {@literal @}UseModules({ FooModule.class, BarModule.class}
     * public class MyTest {
     *   {@literal @}Test
     *   public void someTest(TypeBoundInFooModule a, TypeBoundInBarModule b) {
     *   }
     * }
    * * The example is equivalent to the following inner static module * approach. *
     * {@literal @}RunWith(JukitoRunner.class)
     * public class MyTest {
     *   static class Module extends JukitoModule {
     *     {@literal @}Override
     *     protected void configureTest() {
     *       install(new FooModule());
     *       install(new BarModule());
     *     }
     *   }
     *   // Test methods
     * }
    */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface UseModules { Class[] value(); boolean autoBindMocks() default true; } ================================================ FILE: jukito/src/test/java/org/jukito/AllAnnotationTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.ArrayList; import java.util.List; import org.junit.AfterClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * Test that methods with some parameters annotated with {@literal @}{@link org.jukito.All} behave correctly. */ @RunWith(JukitoRunner.class) public class AllAnnotationTest { /** * Guice test module. */ static class Module extends JukitoModule { @SuppressWarnings("unchecked") @Override protected void configureTest() { bindManyInstances(String.class, "A", "B"); bindManyInstances(TestDataInstance.class, new TestDataInstance("A"), new TestDataInstance("B")); bindMany(TestData.class, TestDataA.class, TestDataB.class); bindMany(Node.class, NodeA.class); } } interface TestData { String getData(); } static class TestDataA implements TestData { public String getData() { return "A"; } } static class TestDataB implements TestData { public String getData() { return "B"; } } static class TestDataInstance { private final String data; TestDataInstance(String data) { this.data = data; } public String getData() { return data; } } interface Node { } static class NodeA implements Node { } /** * This class keeps track of what happens in all the tests run in this * class. It's used to make sure all expected tests are called. */ private static class Bookkeeper { static List stringsProcessed = new ArrayList(); static List dataProcessed = new ArrayList(); static List dataInstanceProcessed = new ArrayList(); } @Test public void testAllWithInstance(@All String string1, @All String string2) { Bookkeeper.stringsProcessed.add(string1 + string2); } @Test public void testAllWithClass(@All TestData data1, @All TestData data2) { Bookkeeper.dataProcessed.add(data1.getData() + data2.getData()); } @Test public void testAllWithClassInstance(@All TestDataInstance data1, @All TestDataInstance data2) { Bookkeeper.dataInstanceProcessed.add(data1.getData() + data2.getData()); } @AfterClass public static void checkBookkeeper() { assertTrue(Bookkeeper.stringsProcessed.contains("AA")); assertTrue(Bookkeeper.stringsProcessed.contains("AB")); assertTrue(Bookkeeper.stringsProcessed.contains("BA")); assertTrue(Bookkeeper.stringsProcessed.contains("BB")); assertEquals(4, Bookkeeper.stringsProcessed.size()); assertTrue(Bookkeeper.dataProcessed.contains("AA")); assertTrue(Bookkeeper.dataProcessed.contains("AB")); assertTrue(Bookkeeper.dataProcessed.contains("BA")); assertTrue(Bookkeeper.dataProcessed.contains("BB")); assertEquals(4, Bookkeeper.dataProcessed.size()); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AB")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BB")); assertEquals(4, Bookkeeper.dataInstanceProcessed.size()); } @Test public void testAllDoesNotIncludeMock(@All Node node, Node neighbour) { assertFalse(Mockito.mockingDetails(node).isMock()); } } ================================================ FILE: jukito/src/test/java/org/jukito/AllNamedAnnotationTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.ArrayList; import java.util.List; import org.junit.AfterClass; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Test that methods with some parameters annotated with {@literal @}{@link All} behave correctly. */ @RunWith(JukitoRunner.class) public class AllNamedAnnotationTest { public static final String FIRST = "first"; public static final String SECOND = "second"; static class Module extends JukitoModule { @SuppressWarnings("unchecked") @Override protected void configureTest() { bindManyNamedInstances(String.class, FIRST, "A", "B"); bindManyNamedInstances(String.class, SECOND, "C", "D"); bindManyNamedInstances(TestDataInstance.class, FIRST, new TestDataInstance("A"), new TestDataInstance("B")); bindManyNamedInstances(TestDataInstance.class, SECOND, new TestDataInstance("C"), new TestDataInstance("D")); bindManyNamed(TestData.class, FIRST, TestDataA.class, TestDataB.class); bindManyNamed(TestData.class, SECOND, TestDataC.class, TestDataD.class); bindManyNamedInstances(Integer.class, null, 1, 2, 3, 5); } } interface TestData { String getData(); } static class TestDataA implements TestData { public String getData() { return "A"; } } static class TestDataB implements TestData { public String getData() { return "B"; } } static class TestDataC implements TestData { public String getData() { return "C"; } } static class TestDataD implements TestData { public String getData() { return "D"; } } static class TestDataInstance { private final String data; TestDataInstance(String data) { this.data = data; } public String getData() { return data; } } /** * This class keeps track of what happens in all the tests run in this * class. It's used to make sure all expected tests are called. */ private static class Bookkeeper { static List namedStringsProcessed = new ArrayList(); static List namedDataProcessed = new ArrayList(); static List namedDataInstanceProcessed = new ArrayList(); static List stringsProcessed = new ArrayList(); static List dataProcessed = new ArrayList(); static List dataInstanceProcessed = new ArrayList(); static List integerProcessed = new ArrayList(); } @Test public void testAllWithNamedInstance(@All(FIRST) String string1, @All(SECOND) String string2) { Bookkeeper.namedStringsProcessed.add(string1 + string2); } @Test public void testAllWithNamedClass(@All(FIRST) TestData data1, @All(SECOND) TestData data2) { Bookkeeper.namedDataProcessed.add(data1.getData() + data2.getData()); } @Test public void testAllWithNamedClassInstance( @All(FIRST) TestDataInstance data1, @All(SECOND) TestDataInstance data2) { Bookkeeper.namedDataInstanceProcessed.add(data1.getData() + data2.getData()); } @Test public void testAllWithInstance(@All String string1, @All String string2) { Bookkeeper.stringsProcessed.add(string1 + string2); } @Test public void testAllWithClass(@All TestData data1, @All TestData data2) { Bookkeeper.dataProcessed.add(data1.getData() + data2.getData()); } @Test public void testAllWithClassInstance(@All TestDataInstance data1, @All TestDataInstance data2) { Bookkeeper.dataInstanceProcessed.add(data1.getData() + data2.getData()); } @Test public void testAllWithNullAsName(@All Integer i) { Bookkeeper.integerProcessed.add(i); } @AfterClass public static void checkBookkeeper() { assertTrue(Bookkeeper.namedStringsProcessed.contains("AC")); assertTrue(Bookkeeper.namedStringsProcessed.contains("AD")); assertTrue(Bookkeeper.namedStringsProcessed.contains("BC")); assertTrue(Bookkeeper.namedStringsProcessed.contains("BD")); assertEquals(4, Bookkeeper.namedStringsProcessed.size()); assertTrue(Bookkeeper.namedDataProcessed.contains("AC")); assertTrue(Bookkeeper.namedDataProcessed.contains("AD")); assertTrue(Bookkeeper.namedDataProcessed.contains("BC")); assertTrue(Bookkeeper.namedDataProcessed.contains("BD")); assertEquals(4, Bookkeeper.namedDataProcessed.size()); assertTrue(Bookkeeper.namedDataInstanceProcessed.contains("AC")); assertTrue(Bookkeeper.namedDataInstanceProcessed.contains("AD")); assertTrue(Bookkeeper.namedDataInstanceProcessed.contains("BC")); assertTrue(Bookkeeper.namedDataInstanceProcessed.contains("BD")); assertEquals(4, Bookkeeper.namedDataInstanceProcessed.size()); assertTrue(Bookkeeper.stringsProcessed.contains("AA")); assertTrue(Bookkeeper.stringsProcessed.contains("AB")); assertTrue(Bookkeeper.stringsProcessed.contains("AC")); assertTrue(Bookkeeper.stringsProcessed.contains("AD")); assertTrue(Bookkeeper.stringsProcessed.contains("BA")); assertTrue(Bookkeeper.stringsProcessed.contains("BB")); assertTrue(Bookkeeper.stringsProcessed.contains("BC")); assertTrue(Bookkeeper.stringsProcessed.contains("BD")); assertTrue(Bookkeeper.stringsProcessed.contains("CA")); assertTrue(Bookkeeper.stringsProcessed.contains("CB")); assertTrue(Bookkeeper.stringsProcessed.contains("CC")); assertTrue(Bookkeeper.stringsProcessed.contains("CD")); assertTrue(Bookkeeper.stringsProcessed.contains("DA")); assertTrue(Bookkeeper.stringsProcessed.contains("DB")); assertTrue(Bookkeeper.stringsProcessed.contains("DC")); assertTrue(Bookkeeper.stringsProcessed.contains("DD")); assertEquals(16, Bookkeeper.stringsProcessed.size()); assertTrue(Bookkeeper.dataProcessed.contains("AA")); assertTrue(Bookkeeper.dataProcessed.contains("AB")); assertTrue(Bookkeeper.dataProcessed.contains("AC")); assertTrue(Bookkeeper.dataProcessed.contains("AD")); assertTrue(Bookkeeper.dataProcessed.contains("BA")); assertTrue(Bookkeeper.dataProcessed.contains("BB")); assertTrue(Bookkeeper.dataProcessed.contains("BC")); assertTrue(Bookkeeper.dataProcessed.contains("BD")); assertTrue(Bookkeeper.dataProcessed.contains("CA")); assertTrue(Bookkeeper.dataProcessed.contains("CB")); assertTrue(Bookkeeper.dataProcessed.contains("CC")); assertTrue(Bookkeeper.dataProcessed.contains("CD")); assertTrue(Bookkeeper.dataProcessed.contains("DA")); assertTrue(Bookkeeper.dataProcessed.contains("DB")); assertTrue(Bookkeeper.dataProcessed.contains("DC")); assertTrue(Bookkeeper.dataProcessed.contains("DD")); assertEquals(16, Bookkeeper.dataProcessed.size()); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AB")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AC")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("AD")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BB")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BC")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("BD")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("CA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("CB")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("CC")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("CD")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("DA")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("DB")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("DC")); assertTrue(Bookkeeper.dataInstanceProcessed.contains("DD")); assertEquals(16, Bookkeeper.dataInstanceProcessed.size()); assertTrue(Bookkeeper.integerProcessed.contains(1)); assertTrue(Bookkeeper.integerProcessed.contains(2)); assertTrue(Bookkeeper.integerProcessed.contains(3)); assertTrue(Bookkeeper.integerProcessed.contains(5)); assertEquals(4, Bookkeeper.integerProcessed.size()); } } ================================================ FILE: jukito/src/test/java/org/jukito/AssistedInjectTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.name.Named; import com.google.inject.name.Names; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; /** * Tests that new Guice 3.0 assisted injection works in Jukito. */ @RunWith(JukitoRunner.class) public class AssistedInjectTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindConstant().annotatedWith(Names.named("G")).to(6.673E-11); install(new FactoryModuleBuilder().implement(Payment.class, RealPayment.class) .build(PaymentFactory.class)); install(new FactoryModuleBuilder().implement(Star.class, StarImpl.class) .build(StarFactory.class)); } } interface PaymentFactory { Payment create(Date startDate, int amount); } interface Payment { String format(); } static class RealPayment implements Payment { private final Date date; private final int amount; private final LocaleInfo localeInfo; @Inject RealPayment(@Assisted Date date, @Assisted int amount, LocaleInfo localeInfo) { this.date = date; this.amount = amount; this.localeInfo = localeInfo; } @Override public String format() { String result = "Paid " + Integer.toString(amount); if (localeInfo.isMoneySignBefore()) { result = localeInfo.getMoneySign() + result; } else { result += localeInfo.getMoneySign(); } SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy", Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("GMT")); result += " on " + formatter.format(date); return result; } } interface LocaleInfo { String getMoneySign(); boolean isMoneySignBefore(); } interface StarFactory { Star create(String name, double mass); } interface Star { double getGravitationalConstant(); double getMass(); String getName(); } static class StarImpl implements Star { private final double gravitationalConstant; private final double mass; private final String name; @Inject StarImpl(@Named("G") Double gravitationalConstant, @Assisted double mass, @Assisted String name) { this.gravitationalConstant = gravitationalConstant; this.mass = mass; this.name = name; } @Override public double getGravitationalConstant() { return gravitationalConstant; } @Override public double getMass() { return mass; } @Override public String getName() { return name; } } @Inject StarFactory starFactory; @Before public void setup(LocaleInfo localeInfo) { when(localeInfo.getMoneySign()).thenReturn("$"); when(localeInfo.isMoneySignBefore()).thenReturn(false); } @Test public void testFactory(PaymentFactory factory) { // GIVEN Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US); calendar.set(2011, 4, 24); // Month is 0-based // WHEN Payment payment = factory.create(calendar.getTime(), 50); // THEN assertEquals("Paid 50$ on 05/24/2011", payment.format()); } @Test public void testFactoryWithInjectedConstant() { // WHEN Star star = starFactory.create("Sun", 1.99E30); // THEN assertEquals("Sun", star.getName()); assertEquals(1.99E30, star.getMass(), 0.000001); assertEquals(6.673E-11, star.getGravitationalConstant(), 0.000001); } } ================================================ FILE: jukito/src/test/java/org/jukito/AutoBindMocksDisabledTest.java ================================================ /* * Copyright 2017 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import com.google.inject.PrivateModule; import jakarta.inject.Inject; /** * Tests behavior of autoBindMocks property on UseModules annotation. * NOTE: If autoBindMocks is true, this test will fail because SomeInterface will be auto bound * to a mock and the binding will conflict with private module's binding */ @RunWith(JukitoRunner.class) @UseModules(value = AutoBindMocksDisabledTest.MyModule.class, autoBindMocks = false) public class AutoBindMocksDisabledTest { /** * Guice PrivateModule for testing. */ public static final class MyModule extends PrivateModule { @Override protected void configure() { bind(ExposedClass.class); bind(SomeInterface.class).to(NotAMock.class); expose(ExposedClass.class); } } /** * Test Interface that will be auto mocked if autoBindMocks is set to true. */ public interface SomeInterface { void doSomething(); } /** * When autoBindMocks is false, an instance of this type will be bound * to SomeInterface from the PrivateModule. */ public static final class NotAMock implements SomeInterface { @Override public void doSomething() { } } /** * Class which injects either the automock or the concrete instance * depending on the autoBindMocks property. */ public static final class ExposedClass { private SomeInterface instance; @Inject ExposedClass(final SomeInterface instance) { this.instance = instance; } SomeInterface getInstance() { return instance; } } @Test public void testSomething(final ExposedClass clazz) throws Exception { Assert.assertFalse(Mockito.mockingDetails(clazz).isMock()); Assert.assertFalse(Mockito.mockingDetails(clazz.getInstance()).isMock()); } } ================================================ FILE: jukito/src/test/java/org/jukito/BindAnnotatedConcreteClassesTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.name.Named; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; /** * Test that annotated concrete classes can be correctly bound. * See http://code.google.com/p/jukito/issues/detail?id=12 */ @RunWith(JukitoRunner.class) public class BindAnnotatedConcreteClassesTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindNamed(ConcreteClass.class, "a").to(ConcreteClass.class).in(TestSingleton.class); bindNamed(ConcreteClass.class, "b").to(ConcreteClass.class).in(TestSingleton.class); bindNamed(ConcreteClass.class, "c").to(SubConcreteClass.class); bindNamed(ConcreteClass.class, "d").to(SubConcreteClass.class); bind(SubConcreteClass.class).in(TestSingleton.class); bind(SubSubConcreteClass.class); } } static class ConcreteClass { } static class SubConcreteClass extends ConcreteClass { } static class SubSubConcreteClass extends ConcreteClass { } @Test public void testConcreteClassBoundToDifferentSingletons(@Named("a") ConcreteClass a, @Named("b") ConcreteClass b) { // THEN assertNotSame(a, b); } @Test public void testConcreteClassBoundToSameSingleton(@Named("c") ConcreteClass c, @Named("d") ConcreteClass d) { // THEN assertSame(c, d); } @Test public void testConcreteClassNoBoundAsSingleton(SubSubConcreteClass instance1, SubSubConcreteClass instance2) { // THEN assertNotSame(instance1, instance2); } } ================================================ FILE: jukito/src/test/java/org/jukito/BindSpyInstanceTest.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Bind spy instance test. */ @RunWith(JukitoRunner.class) public class BindSpyInstanceTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindSpy(SimpleClass.class, new SimpleClass("foo")).in(TestScope.SINGLETON); } } static class SimpleClass { private String arg0; @SuppressWarnings("unused") SimpleClass() { this("default"); } SimpleClass(String arg0) { this.arg0 = arg0; } String getVal() { return arg0; } } @Test public void testOneInvocation(SimpleClass simple) { String value = simple.getVal(); assertEquals("foo", value); verify(simple).getVal(); } @Test public void testNeverInvoked(SimpleClass simple) { verify(simple, never()).getVal(); } } ================================================ FILE: jukito/src/test/java/org/jukito/BindSpyTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that binding spy works correctly. */ @RunWith(JukitoRunner.class) public class BindSpyTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindSpy(SimpleClass.class).in(TestScope.SINGLETON); } } interface CompositionMockA { String test(); } interface CompositionMockB { String test(); } static class SimpleClass { @Inject CompositionMockB mockB; private CompositionMockA mockA; @Inject SimpleClass(CompositionMockA mockA) { this.mockA = mockA; } String callTestMethodOnMock() { mockA.test(); mockB.test(); return "Default string"; } } @Inject CompositionMockA mockA; @Inject CompositionMockA mockB; @Test public void testStubbingSpiedInstance(SimpleClass simpleClass) { // GIVEN doReturn("Mocked string").when(simpleClass).callTestMethodOnMock(); // WHEN String result = simpleClass.callTestMethodOnMock(); // THEN assertEquals("Mocked string", result); verify(mockA, never()).test(); verify(mockB, never()).test(); } @Test public void testNotStubbingSpiedInstance(SimpleClass simpleClass) { // WHEN String result = simpleClass.callTestMethodOnMock(); // THEN verify(mockA).test(); verify(mockB).test(); assertEquals("Default string", result); } } ================================================ FILE: jukito/src/test/java/org/jukito/BindingToProviderTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Provides; import jakarta.inject.Provider; import static org.junit.Assert.assertEquals; /** * A test to make sure injecting a Provider in a @Provides method. * See https://github.com/ArcBees/Jukito/issues/34 */ @RunWith(JukitoRunner.class) public class BindingToProviderTest { /** * Guice test module. */ public static class MyModule extends JukitoModule { @Provides public final MyClass getObject(Provider provider) { return new MyClass("abc" + provider.get()); } @Override protected void configureTest() { bind(String.class).toInstance("def"); } } static class MyClass { private final String string; MyClass(String string) { this.string = string; } String getString() { return string; } } @Test public void foo(MyClass obj) { assertEquals("abcdef", obj.getString()); } } ================================================ FILE: jukito/src/test/java/org/jukito/EDRunner.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.ArrayList; import java.util.List; import org.junit.runner.Description; import org.junit.runner.Runner; import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; /** * Runner allows to run the all test methods in environment build upon different implementations * via dedicated Injectors per test run. */ public class EDRunner extends ParentRunner { private List runnersList; public EDRunner(Class testClass) throws Exception { super(testClass); runnersList = createJukitoRunners(testClass); } public List createJukitoRunners(Class testClass) throws Exception { List result = new ArrayList(); for (Injector injector : calculateInjectors(testClass)) { JukitoRunner jukitoRunner = new JukitoRunner(testClass, injector); result.add(jukitoRunner); } return result; } protected List calculateInjectors(Class testClass) throws IllegalAccessException, InstantiationException { List result = new ArrayList(); EnvironmentDependentModules environmentDependentModules = testClass.getAnnotation(EnvironmentDependentModules.class); if (environmentDependentModules == null) { throw new RuntimeException(EnvironmentDependentModules.class + " not found on test class"); } for (Class edModuleClass : environmentDependentModules.value()) { Injector i = buildInjector(edModuleClass, testClass); result.add(i); } return result; } @Override protected List getChildren() { return runnersList; } @Override protected Description describeChild(Object child) { return ((JukitoRunner) child).getDescription(); } @Override protected void runChild(Object child, RunNotifier notifier) { ((JukitoRunner) child).run(notifier); } private Injector buildInjector(Class edModuleClazz, final Class testClass) throws InstantiationException, IllegalAccessException { final Module environmentDependentModule = edModuleClazz.newInstance(); final AbstractModule testModule = new AbstractModule() { @Override protected void configure() { for (Module declaredModule : getDeclaredModulesForTest(testClass)) { install(declaredModule); } install(environmentDependentModule); } }; JukitoModule finalModule = new JukitoModule() { @Override protected void configureTest() { install(testModule); } }; BindingsCollector collector = new BindingsCollector(finalModule); collector.collectBindings(); finalModule.setBindingsObserved(collector.getBindingsObserved()); return Guice.createInjector(finalModule); } // TODO refactor to common user module discovery method (JukitoRunner uses similar code now) private Module[] getDeclaredModulesForTest(Class testClass) { UseModules useModules = testClass.getAnnotation(UseModules.class); Class[] moduleClasses = useModules.value(); final Module[] modules = new Module[moduleClasses.length]; for (int i = 0; i < modules.length; i++) { try { modules[i] = moduleClasses[i].newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } return modules; } } ================================================ FILE: jukito/src/test/java/org/jukito/EnvironmentDependentComponent.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; /** * Sample interface which have implementations bound in different guice context (Injectors). */ public interface EnvironmentDependentComponent { void hello(); } ================================================ FILE: jukito/src/test/java/org/jukito/ExternalSingleton.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import com.google.inject.Singleton; /** * A class annotated with @Singleton not defined within test class. */ @Singleton public class ExternalSingleton { } ================================================ FILE: jukito/src/test/java/org/jukito/ForceMockTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that the {@link org.jukito.JukitoModule#forceMock} method works as expected. */ @RunWith(JukitoRunner.class) public class ForceMockTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { forceMock(Base1.class); forceMock(Child21.class); forceMock(Child311.class); } } interface Base1 { int t1(); } static class Child11 implements Base1 { public int t1() { return 11; } } static class Child111 extends Child11 { public int t1() { return 111; } } static class Child12 implements Base1 { public int t1() { return 12; } } interface Base2 { int t2(); } static class Child21 implements Base2 { public int t2() { return 21; } } static class Child211 extends Child21 { public int t2() { return 211; } } static class Child22 implements Base2 { public int t2() { return 22; } } interface Base3 { int t3(); } static class Child31 implements Base3 { public int t3() { return 31; } } static class Child311 extends Child31 { public int t3() { return 311; } } @Test public void injectForceMock( Base1 base1, Child11 child11, Child111 child111, Child12 child12, Base2 base2, Child21 child21, Child211 child211, Child22 child22, Base3 base3, Child31 child31, Child311 child311) { verify(base1, never()).t1(); verify(child11, never()).t1(); verify(child111, never()).t1(); verify(child12, never()).t1(); verify(base2, never()).t2(); verify(child21, never()).t2(); verify(child211, never()).t2(); assertEquals(22, child22.t2()); verify(base3, never()).t3(); assertEquals(31, child31.t3()); verify(child311, never()).t3(); } } ================================================ FILE: jukito/src/test/java/org/jukito/GeneralTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.logging.Logger; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.MembersInjector; import com.google.inject.Stage; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; import com.google.inject.name.Names; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test various general behaviors. */ @RunWith(JukitoRunner.class) public class GeneralTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindConstant().annotatedWith(OneHundred.class).to(100); bindConstant().annotatedWith(Names.named("200")).to(200); bindConstant().annotatedWith(Names.named("HelloWorld")).to("Hello World!"); bindConstant().annotatedWith(Names.named("500L")).to(500L); bindConstant().annotatedWith(Names.named("true")).to(true); bindConstant().annotatedWith(Names.named("3.1415")).to(3.1415); bindConstant().annotatedWith(Names.named("2.718f")).to(2.718f); bindConstant().annotatedWith(Names.named("short8")).to((short) 8); bindConstant().annotatedWith(Names.named("'a'")).to('a'); bindConstant().annotatedWith(Names.named("IntegerClass")).to(Integer.class); bindConstant().annotatedWith(Names.named("VALUE1")).to(MyEnum.VALUE1); bindConstant().annotatedWith(Names.named("VALUE2")).to(MyEnum.VALUE2); bind(MyInteger.class).annotatedWith(OneHundred.class).toInstance(new MyIntegerImpl(100)); bind(MyInteger.class).annotatedWith(Names.named("200")).toInstance(new MyIntegerImpl(200)); bind(Key.get(TestClass.class, Value3.class)).toInstance(new TestClass(MyEnum.VALUE3)); bind(Key.get(TestClass.class, Names.named("VALUE2"))).to(TestClass.class).in( TestSingleton.class); bind(new TypeLiteral>() { }).in(TestScope.SINGLETON); bind(new TypeLiteral>() { }).to( ParameterizedTestClassDouble.class).in(TestScope.SINGLETON); bindNamedMock(ClassWithUninstanciableDependency3.class, "UninstanciableDependency3a"); bind(ClassWithUninstanciableDependency3.class).annotatedWith( Names.named("UninstanciableDependency3b")).toProvider(MyMockProvider3b.class); bind(ClassWithUninstanciableDependency3.class).annotatedWith( Names.named("UninstanciableDependency3c")).toProvider(Key.get(MyMockProvider3c.class)); try { bind(ParameterizedTestClassString.class).toConstructor( ParameterizedTestClassString.class.getConstructor(String.class)); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } // TODO: Try to bind a mock logger once Issue 9 is solved. // bindMock(Logger.class); } } interface MyInteger { int getValue(); } static class MyIntegerImpl implements MyInteger { private final int value; MyIntegerImpl(int value) { this.value = value; } @Override public int getValue() { return value; } } enum MyEnum { VALUE1, VALUE2, VALUE3 } static class TestClass { private final MyEnum value; @Inject TestClass(@Named("VALUE2") MyEnum value) { this.value = value; } } static class ParameterizedTestClass { final T value; @Inject ParameterizedTestClass(@Named("200") T value) { this.value = value; } } static class ParameterizedTestClassDouble extends ParameterizedTestClass { @Inject ParameterizedTestClassDouble() { super(10.0); } } public static class ParameterizedTestClassString extends ParameterizedTestClass { ParameterizedTestClassString() { super("default constructor"); } public ParameterizedTestClassString(@Named("HelloWorld") String value) { super(value); } } static class TestClassWithMethodInjection { private int value; @Inject TestClassWithMethodInjection(@OneHundred Integer value) { this.value = value; } @Inject public void setValue(@Named("200") Integer value) { this.value = value; } } interface NonBoundInterface { int getValue(); } static class TestClassWithOptionalInjection { private int value; @Inject TestClassWithOptionalInjection(@OneHundred Integer value) { this.value = value; } @Inject(optional = true) public void setValue(NonBoundInterface obj) { value = obj.getValue(); // Should never be called, NonBoundInterface should not be mocked } } // This class will cause an error if bound static class UninstanciableClass { private UninstanciableClass() { } public int getValue() { return 360; } } @TestMockSingleton static class ClassWithUninstanciableDependency1 { private final UninstanciableClass dependency; @Inject ClassWithUninstanciableDependency1(UninstanciableClass dependency) { this.dependency = dependency; } public int getValue() { return 42; } public UninstanciableClass getDependency() { return dependency; } } abstract static class ClassWithUninstanciableDependency2 { @Inject ClassWithUninstanciableDependency2(UninstanciableClass dependency) { } public int getValue() { return 42; } } static class ClassWithUninstanciableDependency3 { @Inject ClassWithUninstanciableDependency3(UninstanciableClass dependency) { } public int getValue() { return 42; } } static class MyMockProvider3b extends MockProvider { @Inject MyMockProvider3b() { super(ClassWithUninstanciableDependency3.class); } } static class MyMockProvider3c extends MockProvider { @Inject MyMockProvider3c() { super(ClassWithUninstanciableDependency3.class); } } static class TestGenericClassInjectedWithTypeLiteral { private final Class injectedType; @Inject TestGenericClassInjectedWithTypeLiteral(TypeLiteral typeLiteral) { injectedType = typeLiteral.getRawType(); } public Class getInjectedType() { return injectedType; } } @Test public void testConstantInjection( @OneHundred Integer oneHundred, @Named("200") Integer twoHundred, @Named("HelloWorld") String helloWorld, @Named("500L") long fiveHundred, @Named("3.1415") double pi, @Named("2.718f") float e, @Named("short8") short eight, @Named("'a'") char a, @SuppressWarnings("rawtypes") @Named("IntegerClass") Class integerClass, @Named("VALUE1") MyEnum value1) { assertEquals(100, (int) oneHundred); assertEquals(200, (int) twoHundred); assertEquals("Hello World!", helloWorld); assertEquals(500L, fiveHundred); assertEquals(3.1415, pi, 0.0000001); assertEquals(2.718f, e, 0.00001); assertEquals(8, eight); assertEquals('a', a); assertEquals(Integer.class, integerClass); assertEquals(MyEnum.VALUE1, value1); } @Test public void testInjectBoundWithKeys( @Value3 TestClass testClassValue3, @Named("VALUE2") TestClass testClassValue2, @OneHundred MyInteger testMyInteger100, @Named("200") MyInteger testMyInteger200) { assertEquals(MyEnum.VALUE3, testClassValue3.value); assertEquals(MyEnum.VALUE2, testClassValue2.value); assertEquals(100, testMyInteger100.getValue()); assertEquals(200, testMyInteger200.getValue()); } @Test public void testParameterizedInjection1( ParameterizedTestClass testClass) { assertEquals(200, (int) testClass.value); } @Test public void testParameterizedInjection2( ParameterizedTestClass testClass) { assertEquals(10.0, (double) testClass.value, 0.0000001); } @Test public void testMethodInjection( TestClassWithMethodInjection testClass) { assertEquals(200, testClass.value); } @Test public void testOptionalInjection( TestClassWithOptionalInjection testClass) { assertEquals(100, testClass.value); } @Test public void testInjectingMockShouldNotInstantiateDependencies1( ClassWithUninstanciableDependency1 testClass) { assertEquals(42, testClass.getValue()); verify(testClass.getDependency(), never()).getValue(); } @Test public void testInjectingMockShouldNotInstantiateDependencies2( ClassWithUninstanciableDependency2 testClass) { verify(testClass, never()).getValue(); } @Test public void testInjectingMockShouldNotInstantiateDependencies3a( @Named("UninstanciableDependency3a") ClassWithUninstanciableDependency3 testClass) { verify(testClass, never()).getValue(); } @Test public void testInjectingMockShouldNotInstantiateDependencies3b( @Named("UninstanciableDependency3b") ClassWithUninstanciableDependency3 testClass) { verify(testClass, never()).getValue(); } @Test public void testInjectingMockShouldNotInstantiateDependencies3c( @Named("UninstanciableDependency3c") ClassWithUninstanciableDependency3 testClass) { verify(testClass, never()).getValue(); } @Test public void testInjectingClassInjectedWithTypeLiteralShouldWork( TestGenericClassInjectedWithTypeLiteral testClass) { assertEquals(String.class, testClass.getInjectedType()); } @Test public void testInjectingTypeLiteralShouldWork( TypeLiteral typeLiteral) { assertEquals(Integer.class, typeLiteral.getRawType()); } @Test public void testInjectingInjectorShouldWork( Injector injector) { } @Test public void testInjectingLoggerShouldWork( Logger logger) { } @Test public void testInjectingStageShouldWork( Stage stage) { } @Test public void testInjectingMembersInjectorShouldWork( MembersInjector memberInjector) { } @Test public void toConstructorInjectionShouldWork(ParameterizedTestClassString object) { assertEquals("Hello World!", object.value); } } ================================================ FILE: jukito/src/test/java/org/jukito/InnerClassTest.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.ConfigurationException; import com.google.inject.Inject; import static org.junit.Assert.assertEquals; /** * Test to ensure that injecting inner classes throw a ConfigurationException, instead * of simply injecting a mock. Additionally, test that injecting static inner classes * still work properly. */ @RunWith(JukitoRunner.class) public class InnerClassTest { /** * Test module, just bind anything to make sure regular injections still work properly. */ public static class Module extends JukitoModule { @Override protected void configureTest() { bind(String.class).toInstance("hello world!"); } } /** * Dummy inner class with a single inject. */ class InnerClass { @Inject String test; public String toString() { return test; } } /** * Dummy static inner class with a single inject. */ static class StaticInnerClass { @Inject String test; public String toString() { return test; } } /** * Verify that when you try to inject an inner class, a ConfigurationException is thrown. * * @param klass */ @Test(expected = ConfigurationException.class) public void testInnerClass(InnerClass klass) { assertEquals("hello world!", klass.toString()); } /** * Verify that when you try to inject a static inner class, everything works properly. * * @param klass */ @Test public void testStaticInnerClass(StaticInnerClass klass) { assertEquals("hello world!", klass.toString()); } } ================================================ FILE: jukito/src/test/java/org/jukito/InstallTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.name.Named; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; /** * Test exercising Guice's install() mechanism. */ @RunWith(JukitoRunner.class) public class InstallTest { /** * Guice test module, containing two submodules. */ static class Module extends JukitoModule { public class FooModule extends AbstractModule { @Override protected void configure() { bind(Foo.class).to(FooImpl.class); } } public class BarModule extends AbstractModule { @Override protected void configure() { bind(Bar.class).to(BarImpl.class); } } @Override protected void configureTest() { install(new FooModule()); install(new BarModule()); bindNamedMock(Foo.class, "ten").in(TestSingleton.class); } } interface Foo { int calc(); } static class FooImpl implements Foo { private final Provider barProvider; private final Foo ten; @Inject FooImpl(Provider barProvider, @Named("10") Foo ten) { this.barProvider = barProvider; this.ten = ten; } @Override public int calc() { return this.barProvider.get().calc() + ten.calc(); } } interface Bar { int calc(); } static class BarImpl implements Bar { @Override public int calc() { return 5; } } @Inject Foo foo; @Before public void setup(@Named("10") Foo ten) { when(ten.calc()).thenReturn(10); } @Test public void installingModuleWorks(Bar bar) { assertEquals(15, foo.calc()); assertEquals(5, bar.calc()); } } ================================================ FILE: jukito/src/test/java/org/jukito/ModuleWithProvidesMethods.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import com.google.inject.AbstractModule; import com.google.inject.Provides; import static org.mockito.Mockito.mock; /** * Simple module with factory method. */ public class ModuleWithProvidesMethods extends AbstractModule { @Provides @TestSingleton SomeTestClass create() { SomeTestClass mock = mock(SomeTestClass.class); mock.someInitMethod(); return mock; } @Override protected void configure() { } } ================================================ FILE: jukito/src/test/java/org/jukito/NoModuleTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.verify; /** * Test to ensure injection works well without a module. */ @RunWith(JukitoRunner.class) public class NoModuleTest { interface MyMockSingleton { int dummy(); } @TestMockSingleton interface MyAnnotatedMockSingleton { int dummy(); } static class MySingleton { } @TestSingleton static class MyAnnotatedSingleton { } @TestEagerSingleton static class MyAnnotatedEagerSingleton { } @Test public void testMockSingleton(MyMockSingleton a, MyMockSingleton b) { assertSame(a, b); a.dummy(); verify(a).dummy(); verify(b).dummy(); } @Test public void testAnnotatedMockSingleton(MyAnnotatedMockSingleton a, MyAnnotatedMockSingleton b) { assertSame(a, b); a.dummy(); verify(a).dummy(); verify(b).dummy(); } @Test public void testSingleton(MySingleton a, MySingleton b) { assertSame(a, b); } @Test public void testAnnotatedSingleton(MyAnnotatedSingleton a, MyAnnotatedSingleton b) { assertSame(a, b); } @Test public void testAnnotatedEagerSingleton(MyAnnotatedEagerSingleton a, MyAnnotatedEagerSingleton b) { assertSame(a, b); } } ================================================ FILE: jukito/src/test/java/org/jukito/OldStyleAssistedInjectTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.FactoryProvider; import com.google.inject.name.Named; import com.google.inject.name.Names; import static org.junit.Assert.assertEquals; /** * Test that make sure old-style Guice 2.0 assisted injection is supported. */ @SuppressWarnings("deprecation") @RunWith(JukitoRunner.class) public class OldStyleAssistedInjectTest { /** * Guice test module. */ public static class Module extends JukitoModule { @Override protected void configureTest() { bindConstant().annotatedWith(Names.named("moneySymbol")).to("$"); bindNamed(PaymentFactory.class, "factory1").toProvider( FactoryProvider.newFactory(PaymentFactory.class, RealPayment1.class)); bindNamed(PaymentFactory.class, "factory2").toProvider( FactoryProvider.newFactory(PaymentFactory.class, RealPayment2.class)); bind(PaymentAmountFactory.class).toProvider( FactoryProvider.newFactory(PaymentAmountFactory.class, RealPaymentAmount.class)); bind(Amount.class).toInstance(new Amount() { public String toString() { return "An amount of 10.00 "; } }); } } interface PaymentFactory { Payment create(int amount); } interface PaymentAmountFactory { Payment create(Amount amount); } interface Payment { String getPayment(); } static class RealPayment1 implements Payment { private final String moneySymbol; private final int amount; @Inject RealPayment1(@Named("moneySymbol") String moneySymbol, @Assisted int amount) { this.moneySymbol = moneySymbol; this.amount = amount; } @Override public String getPayment() { return Integer.toString(amount) + ".00" + moneySymbol; } } static class RealPayment2 implements Payment { private final int amount; @Inject RealPayment2(@Assisted int amount) { this.amount = amount; } @Override public String getPayment() { return Integer.toString(amount) + " dollars"; } } interface Amount { String toString(); } // Interface Configuration should be mocked because it is a dependency // of RealPaymentAmout. The mocked version of {@ocde shouldAlwaysHideAmounts()} // will always return {@code false}. interface Configuration { boolean shouldAlwaysHideAmounts(); } // Class InjectedClass should be bound automatically // because it is a dependency of RealPaymentAmount static class InjectedClass { @Inject @Named("moneySymbol") String moneySymbol; } static class RealPaymentAmount implements Payment { private final Configuration configuration; private final InjectedClass injectedClass; private final Amount amount; @Inject RealPaymentAmount(Configuration configuration, InjectedClass injectedClass, @Assisted Amount amount) { this.configuration = configuration; this.injectedClass = injectedClass; this.amount = amount; } @Override public String getPayment() { if (configuration.shouldAlwaysHideAmounts()) { return "xxxxxxx " + injectedClass.moneySymbol; } return amount.toString() + injectedClass.moneySymbol; } } @Inject @Named("factory1") PaymentFactory factory1; @Test public void shouldInjectFactoryInClass() { // WHEN Payment payment = factory1.create(20); // THEN assertEquals("20.00$", payment.getPayment()); } @Test public void shouldInjectFactoryAsParameter(@Named("factory2") PaymentFactory factory2) { // WHEN Payment payment = factory2.create(30); // THEN assertEquals("30 dollars", payment.getPayment()); } @Test public void shouldInjectFactoryWithInterfacesAsParameter( PaymentAmountFactory factoryString, Amount amount) { // WHEN Payment payment = factoryString.create(amount); // THEN assertEquals("An amount of 10.00 $", payment.getPayment()); } } ================================================ FILE: jukito/src/test/java/org/jukito/OneHundred.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.google.inject.BindingAnnotation; /** * An annotation used in a test class. */ @BindingAnnotation @Retention(RetentionPolicy.RUNTIME) public @interface OneHundred { } ================================================ FILE: jukito/src/test/java/org/jukito/ParentClassInnerClassModuleDiscoveryTest.java ================================================ /* * Copyright 2017 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.concurrent.atomic.AtomicInteger; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; /** * Test which ensures that nested TestModules in parent classes are discovered by the JukitoRunner. */ @RunWith(JukitoRunner.class) public class ParentClassInnerClassModuleDiscoveryTest extends SampleParentTestClassWithInnerTestModule { private static final AtomicInteger numberOfTestRuns = new AtomicInteger(0); @AfterClass public static void afterClass() throws Exception { Assert.assertEquals(2, numberOfTestRuns.get()); } @Test public void testSomething(@All final String bindingsFromParent) throws Exception { numberOfTestRuns.incrementAndGet(); } } ================================================ FILE: jukito/src/test/java/org/jukito/ParentTestClassBase.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import com.google.inject.Inject; import com.google.inject.Provider; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * This parent test class is used by {@link ParentTestClassTest}. */ @Ignore("Tests in this base class are not meant to be run independantly.") public class ParentTestClassBase { /** * This should be automatically injected in the child class. */ @TestSingleton static class SingletonDefinedInParent { private String value = "SingletonDefinedInParentValue"; public String getValue() { return value; } } /** * This should be automatically injected in the child class. */ @TestMockSingleton interface MockSingletonDefinedInParent { void mockSingletonMethod(); } interface DummyInterface { String getDummyValue(); } interface DummyInterfaceUsedOnlyInParent1 { String getDummyValue(); } interface DummyInterfaceUsedOnlyInParent2 { String getDummyValue(); } interface DummyInterfaceUsedOnlyInParent3 { String getDummyValue(); } static class DummyClassUsedOnlyInParent1 { } static class DummyClassUsedOnlyInParent2 { } static class DummyClassUsedOnlyInParent3 { } @Inject protected Provider dummyProvider; @Inject protected MockSingletonDefinedInParent mockSingletonDefinedInParent; /** * This class keeps track of what happens in all the tests run in this * class and its child. It's used to make sure all expected tests are called. */ protected static class Bookkeeper { static boolean parentTestShouldRunExecuted; } @Test public void parentTestShouldRun() { Bookkeeper.parentTestShouldRunExecuted = true; } @Test public void interfaceBoundInChildIsInjectedInParent() { assertEquals("DummyValue", dummyProvider.get().getDummyValue()); } @Test public void interfaceBoundInChildIsInjectedInParentTestMethod( DummyInterface dummyInterface) { assertEquals("DummyValue", dummyInterface.getDummyValue()); } @Test public void interfaceUsedInParentTestMethodShouldBeMockedAsTestSingleton( Provider provider) { // Following should not crash verify(provider.get(), never()).getDummyValue(); assertSame(provider.get(), provider.get()); } @Test public void concreteClassUsedInParentTestMethodShouldBeBoundAsTestSingleton( Provider provider) { assertSame(provider.get(), provider.get()); } @Before public void interfaceUsedInParentBeforeMethodShouldBeMockedAsTestSingleton( Provider provider) { // Following should not crash verify(provider.get(), never()).getDummyValue(); assertSame(provider.get(), provider.get()); } @Before public void concreteClassUsedInParentBeforeMethodShouldBeBoundAsTestSingleton( Provider provider) { assertSame(provider.get(), provider.get()); } @After public void interfaceUsedInParentAfterMethodShouldBeMockedAsTestSingleton( Provider provider) { // Following should not crash verify(provider.get(), never()).getDummyValue(); assertSame(provider.get(), provider.get()); } @After public void concreteClassUsedInParentAfterMethodShouldBeBoundAsTestSingleton( Provider provider) { assertSame(provider.get(), provider.get()); } } ================================================ FILE: jukito/src/test/java/org/jukito/ParentTestClassTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.AfterClass; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that inheritance of test classes works correctly. */ @RunWith(JukitoRunner.class) public class ParentTestClassTest extends ParentTestClassBase { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bind(DummyInterface.class).to(MyDummyClass.class).in(TestScope.SINGLETON); } } /** * This class should be injected in parent tests. */ static class MyDummyClass implements DummyInterface { @Override public String getDummyValue() { return "DummyValue"; } } @Test public void mockSingletonDefinedInParentShouldBeBoundAsAMock() { verify(mockSingletonDefinedInParent, never()).mockSingletonMethod(); } @Test public void singletonDefinedInParentShouldBeBound( SingletonDefinedInParent singletonDefinedInParent) { assertEquals("SingletonDefinedInParentValue", singletonDefinedInParent.getValue()); } @AfterClass public static void checkBookkeeper() { assertTrue(Bookkeeper.parentTestShouldRunExecuted); } } ================================================ FILE: jukito/src/test/java/org/jukito/ProviderBindingTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import com.google.inject.Inject; import com.google.inject.Provider; import static junit.framework.Assert.assertNotNull; /** * Test which ensures that a class which is a provider may also be binded independently. */ @RunWith(JukitoRunner.class) public class ProviderBindingTest { /** * Guice test module. */ public static class Module extends JukitoModule { @Override protected void configureTest() { bind(ServiceAndProvider.class); bind(MyService.class).toProvider(ServiceAndProvider.class); } } @Test public void shouldBeExecuted(OtherService service, MyService myService) { assertNotNull(service); assertNotNull(myService); } interface MyService { } static class ServiceAndProvider implements Provider { @Override public MyService get() { return Mockito.mock(MyService.class); } public void doSomethingVeryImportant() { // nop } } static class OtherService { @Inject public ServiceAndProvider service; } } ================================================ FILE: jukito/src/test/java/org/jukito/ProviderTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.name.Named; import com.google.inject.name.Names; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that providers injected by the tester module behaves correctly. */ @RunWith(JukitoRunner.class) public class ProviderTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindNamedMock(Mock.class, "singleton").in(TestScope.SINGLETON); bindNamedMock(Mock.class, "nonsingleton"); bindNamed(Instance.class, "singleton").to(Instance.class).in(TestSingleton.class); bindNamed(Instance.class, "nonsingleton").to(Instance.class); bindNamed(Parent.class, "providerInstance").toProvider(new ParentProviderA()).in( TestSingleton.class); bindNamed(Parent.class, "providerClass").toProvider(ParentProviderB.class).in( TestSingleton.class); bindNamed(Parent.class, "providerKey").toProvider(Key.get(ParentProviderA.class)).in( TestSingleton.class); bindNamedMock(UninstanciableClass.class, "cannotInstantiate1").in(TestScope.SINGLETON); bind(UninstanciableClass.class).annotatedWith(Names.named("cannotInstantiate2")).toProvider( MyMockProvider2.class); bind(UninstanciableClass.class).annotatedWith(Names.named("cannotInstantiate3")).toProvider( Key.get(MyMockProvider3.class)); bind(ClassWithMockedDependency1.class).annotatedWith( Names.named("MockedDependency1")).toProvider(MyProvider1.class); bind(ClassWithMockedDependency2.class).annotatedWith( Names.named("MockedDependency2")).toProvider(Key.get(MyProvider2.class)); } @Provides ProvidedViaMethod getProvidedViaMethod() { return new ProvidedViaMethod("good"); } } interface Mock { } static class Instance { @Inject Instance() { } } interface Parent { String getValue(); } static class ChildA implements Parent { public String getValue() { return "childA"; } } interface MockInChildB { } interface MockInProviderB { void test(); } static class ChildB implements Parent { @Inject MockInChildB mockB; public String getValue() { return "childB"; } } abstract static class ParentProviderABase implements Provider { } static class ParentProviderA extends ParentProviderABase { @Override public Parent get() { return new ChildA(); } } static class ParentProviderB implements Provider { private final Provider childBProvider; @Inject ParentProviderB(Provider childBProvider, Provider myMock) { this.childBProvider = childBProvider; // These calls should succeed myMock.get().test(); verify(myMock.get()).test(); } @Override public Parent get() { return childBProvider.get(); } } static class UninstanciableClass { private UninstanciableClass() { } public int getValue() { return 42; } } static class MyMockProvider2 extends MockProvider { @Inject MyMockProvider2() { super(UninstanciableClass.class); } } static class MyMockProvider3 extends MockProvider { @Inject MyMockProvider3() { super(UninstanciableClass.class); } } interface DependencyShouldBeMocked1 { int getValue(); } static class ClassWithMockedDependency1 { private final DependencyShouldBeMocked1 dependency; @Inject ClassWithMockedDependency1(DependencyShouldBeMocked1 dependency) { this.dependency = dependency; } public DependencyShouldBeMocked1 getDependency() { return dependency; } } static class MyProvider1 implements Provider { final Provider provider; @Inject MyProvider1(Provider provider) { this.provider = provider; } @Override public ClassWithMockedDependency1 get() { return provider.get(); } } interface DependencyShouldBeMocked2 { int getValue(); } static class ClassWithMockedDependency2 { private final DependencyShouldBeMocked2 dependency; @Inject ClassWithMockedDependency2(DependencyShouldBeMocked2 dependency) { this.dependency = dependency; } public DependencyShouldBeMocked2 getDependency() { return dependency; } } static class MyProvider2 implements Provider { final Provider provider; @Inject MyProvider2(Provider provider) { this.provider = provider; } @Override public ClassWithMockedDependency2 get() { return provider.get(); } } static class ProvidedViaMethod { final String value; ProvidedViaMethod(String value) { this.value = value; } } @Test public void mockSingletonProviderShouldReturnTheSameInstance( @Named("singleton") Provider provider) { assertSame(provider.get(), provider.get()); } @Test public void mockNonSingletonProviderShouldNotReturnTheSameInstance( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void singletonProvidedClassShouldReturnTheSameInstance( @Named("singleton") Provider provider) { assertSame(provider.get(), provider.get()); } @Test public void singletonClassShouldNotReturnTheSameInstance( @Named("singleton") Instance obj1, @Named("singleton") Instance obj2) { assertSame(obj1, obj2); } @Test public void nonSingletonProvidedClassShouldNotReturnTheSameInstance( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void nonSingletonClassShouldNotReturnTheSameInstance( @Named("nonsingleton") Instance obj1, @Named("nonsingleton") Instance obj2) { assertNotSame(obj1, obj2); } @Test public void bindingToProviderInstanceShouldWorkAndInject( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void shouldInjectProviderBoundWithInstance( @Named("providerInstance") Parent parentProvidedFromProviderInstance) { assertEquals(parentProvidedFromProviderInstance.getClass(), ChildA.class); } @Test public void shouldInjectProviderBoundWithClass( @Named("providerClass") Parent parentProvidedFromProviderClass) { assertEquals(parentProvidedFromProviderClass.getClass(), ChildB.class); } @Test public void shouldInjectProviderBoundWithKey( @Named("providerKey") Parent parentProvidedFromProviderKey) { assertEquals(parentProvidedFromProviderKey.getClass(), ChildA.class); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor1( @Named("cannotInstantiate1") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor2( @Named("cannotInstantiate2") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor3( @Named("cannotInstantiate3") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void testInjectingProviderShouldInstantiateDependencies1( @Named("MockedDependency1") ClassWithMockedDependency1 testClass) { verify(testClass.getDependency(), never()).getValue(); } @Test public void testInjectingProviderShouldInstantiateDependencies2( @Named("MockedDependency2") ClassWithMockedDependency2 testClass) { verify(testClass.getDependency(), never()).getValue(); } @Test public void providesMethodShouldWork(ProvidedViaMethod providedViaMethod) { assertEquals("good", providedViaMethod.value); } } ================================================ FILE: jukito/src/test/java/org/jukito/ProvidesMethodTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.name.Named; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that @Provides methods in the tester module behave correctly. */ @RunWith(JukitoRunner.class) public class ProvidesMethodTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bindNamedMock(Mock.class, "singleton").in(TestScope.SINGLETON); bindNamedMock(Mock.class, "nonsingleton"); bindNamed(Instance.class, "singleton").to(Instance.class).in(TestSingleton.class); bindNamed(Instance.class, "nonsingleton").to(Instance.class); bindNamedMock(UninstanciableClass.class, "cannotInstantiate1").in(TestScope.SINGLETON); } @Provides @TestSingleton @Named("providerInstance") protected Parent providesParent1() { return new ChildA(); } @Provides @TestSingleton @Named("providerClass") protected Parent providesParent2(ChildB childB, MockInProviderB myMock) { // These calls should succeed myMock.test(); verify(myMock).test(); return childB; } @Provides @TestSingleton @Named("providerKey") protected Parent providesParent3() { return new ChildA(); } @Provides @TestSingleton @Named("cannotInstantiate2") protected UninstanciableClass providesUninstanciableClass2() { return mock(UninstanciableClass.class); } @Provides @TestSingleton @Named("cannotInstantiate3") protected UninstanciableClass providesUninstanciableClass3() { return mock(UninstanciableClass.class); } @Provides @TestSingleton @Named("MockedDependency1") protected ClassWithMockedDependency1 providesClassWithMockedDependency1(ClassWithMockedDependency1 x) { return x; } @Provides @TestSingleton @Named("MockedDependency2") protected ClassWithMockedDependency2 providesClassWithMockedDependency2(ClassWithMockedDependency2 x) { return x; } @Provides public Value aValue() { return VALUE; } @Provides public Integer anInteger(Value value) { return 3; } } interface Mock { } static class Instance { @Inject Instance() { } } interface Parent { String getValue(); } static class ChildA implements Parent { public String getValue() { return "childA"; } } interface MockInChildB { } interface MockInProviderB { void test(); } static class ChildB implements Parent { @Inject MockInChildB mockB; public String getValue() { return "childB"; } } static class UninstanciableClass { private UninstanciableClass() { } public int getValue() { return 42; } } interface DependencyShouldBeMocked1 { int getValue(); } static class ClassWithMockedDependency1 { private final DependencyShouldBeMocked1 dependency; @Inject ClassWithMockedDependency1(DependencyShouldBeMocked1 dependency) { this.dependency = dependency; } public DependencyShouldBeMocked1 getDependency() { return dependency; } } interface DependencyShouldBeMocked2 { int getValue(); } static class ClassWithMockedDependency2 { private final DependencyShouldBeMocked2 dependency; @Inject ClassWithMockedDependency2(DependencyShouldBeMocked2 dependency) { this.dependency = dependency; } public DependencyShouldBeMocked2 getDependency() { return dependency; } } static class Value { public final String string; Value(String string) { this.string = string; } } private static final Value VALUE = new Value("ok"); @Test public void mockSingletonProviderShouldReturnTheSameInstance( @Named("singleton") Provider provider) { assertSame(provider.get(), provider.get()); } @Test public void mockNonSingletonProviderShouldNotReturnTheSameInstance( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void singletonProvidedClassShouldReturnTheSameInstance( @Named("singleton") Provider provider) { assertSame(provider.get(), provider.get()); } @Test public void singletonClassShouldNotReturnTheSameInstance( @Named("singleton") Instance obj1, @Named("singleton") Instance obj2) { assertSame(obj1, obj2); } @Test public void nonSingletonProvidedClassShouldNotReturnTheSameInstance( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void nonSingletonClassShouldNotReturnTheSameInstance( @Named("nonsingleton") Instance obj1, @Named("nonsingleton") Instance obj2) { assertNotSame(obj1, obj2); } @Test public void bindingToProviderInstanceShouldWorkAndInject( @Named("nonsingleton") Provider provider) { assertNotSame(provider.get(), provider.get()); } @Test public void shouldInjectProviderBoundWithInstance( @Named("providerInstance") Parent parentProvidedFromProviderInstance) { assertEquals(parentProvidedFromProviderInstance.getClass(), ChildA.class); } @Test public void shouldInjectProviderBoundWithClass( @Named("providerClass") Parent parentProvidedFromProviderClass) { assertEquals(parentProvidedFromProviderClass.getClass(), ChildB.class); } @Test public void shouldInjectProviderBoundWithKey( @Named("providerKey") Parent parentProvidedFromProviderKey) { assertEquals(parentProvidedFromProviderKey.getClass(), ChildA.class); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor1( @Named("cannotInstantiate1") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor2( @Named("cannotInstantiate2") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void shouldInjectProviderOfClassWithPrivateConstructor3( @Named("cannotInstantiate3") UninstanciableClass classWithPrivateConstructor) { verify(classWithPrivateConstructor, never()).getValue(); } @Test public void testInjectingProviderShouldInstantiateDependencies1( @Named("MockedDependency1") ClassWithMockedDependency1 testClass) { verify(testClass.getDependency(), never()).getValue(); } @Test public void testInjectingProviderShouldInstantiateDependencies2( @Named("MockedDependency2") ClassWithMockedDependency2 testClass) { verify(testClass.getDependency(), never()).getValue(); } @Test public void testProvidingConstants(Value value, Integer integer) { assertEquals("ok", value.string); assertEquals(3, (int) integer); } } ================================================ FILE: jukito/src/test/java/org/jukito/ReportWriterTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.io.StringWriter; import java.io.Writer; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import jakarta.inject.Singleton; import static org.junit.Assert.assertEquals; /** * Tests that new Guice 3.0 assisted injection works in Jukito. */ @RunWith(JukitoRunner.class) public class ReportWriterTest { /** * Guice test module. */ static class Module extends JukitoModule { final Writer reportWriter = new StringWriter(); // Overriding this method will cause a report to be generated. @Override public Writer getReportWriter() { return reportWriter; } @Override protected void configureTest() { bind(Writer.class).toInstance(reportWriter); bindNamedSpy(Resource4.class, "Spy").in(TestSingleton.class); forceMock(Resource6.class); } } @Singleton static class Resource1 { } interface Resource2 { } static class Resource3 { @Inject @OneHundred Resource5 resource5; @Inject Resource3(Resource4 resource4) { } @Inject void setResource6(Resource6 resource6) { } } static class Resource4 { } interface Resource5 { } static class Resource6 { } @Inject Resource2 resource2; @Inject Resource3 resource3; @Test public void ensureReport(Writer reportWriter, Resource1 resource1) { Set explicitBindings = findBlock("*** EXPLICIT BINDINGS ***", reportWriter.toString()); Set automaticBindings = findBlock("*** AUTOMATIC BINDINGS ***", reportWriter.toString()); Set e = new HashSet(); e.add(" Key[type=java.io.Writer, annotation=[none]] --> Instance of java.io.StringWriter ### In scope " + "EagerSingleton"); e.add(" Key[type=org.jukito.ReportWriterTest$Resource4, annotation=@org.jukito.JukitoInternal] --> Bound " + "directly ### No scope"); e.add(" Key[type=org.jukito.ReportWriterTest$Resource4, annotation=@com.google.inject.name.Named(\"Spy\")]" + " " + "--> Instance of org.jukito.SpyProvider ### In scope org.jukito.TestSingleton"); Set a = new HashSet(); a.add(" Key[type=org.jukito.ReportWriterTest$Resource1, annotation=[none]] --> Bound directly ### In scope " + "TestSingleton"); a.add(" Key[type=org.jukito.ReportWriterTest$Resource2, annotation=[none]] --> Instance of " + "org.jukito.MockProvider ### In scope TestSingleton"); a.add(" Key[type=org.jukito.ReportWriterTest$Resource3, annotation=[none]] --> Bound directly ### In scope " + "TestSingleton"); a.add(" Key[type=org.jukito.ReportWriterTest$Resource4, annotation=[none]] --> Bound directly ### In scope " + "TestSingleton"); a.add(" Key[type=org.jukito.ReportWriterTest$Resource5, annotation=@org.jukito.OneHundred] --> Instance of " + "org.jukito.MockProvider ### In scope TestSingleton"); a.add(" Key[type=org.jukito.ReportWriterTest$Resource6, annotation=[none]] --> Instance of " + "org.jukito.MockProvider ### In scope TestSingleton"); assertEquals(e, explicitBindings); assertEquals(a, automaticBindings); } private Set findBlock(String header, String text) { int start = text.indexOf(header) + header.length(); int end = text.indexOf("\n\n", start); String block = text.substring(start + 1, end); String[] lines = block.split("\n"); Set result = new HashSet(lines.length); result.addAll(Arrays.asList(lines)); return result; } } ================================================ FILE: jukito/src/test/java/org/jukito/RequestInjectionTest.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import jakarta.inject.Inject; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mockingDetails; /** * Test class for request injection. */ @RunWith(JukitoRunner.class) public class RequestInjectionTest { interface Dummy { } static class RequestInjection { @Inject Dummy dummy; public Dummy getDummy() { return dummy; } } static class Module extends JukitoModule { @Override protected void configureTest() { requestInjection(RequestInjection.class); } } // SUT @Inject RequestInjection requestInjection; @Test public void dummyShouldBeMocked() { Dummy dummy = requestInjection.getDummy(); assertTrue(mockingDetails(dummy).isMock()); } } ================================================ FILE: jukito/src/test/java/org/jukito/RequestStaticInjectionTest.java ================================================ /** * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Provides; import jakarta.inject.Inject; import jakarta.inject.Named; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mockingDetails; /** * Test class for request static injection. */ @RunWith(JukitoRunner.class) public class RequestStaticInjectionTest { interface Dummy { } static class RequestStaticInjectionA { @Inject @Named("a") static Dummy DUMMY; } static class RequestStaticInjectionB { @Inject static Dummy DUMMY; } static class Module extends JukitoModule { @Override protected void configureTest() { requestStaticInjection(RequestStaticInjectionA.class); requestStaticInjection(RequestStaticInjectionB.class); } @Provides @Named("a") Dummy createDummy() { return new Dummy() { }; } } @Test public void dummyShouldNotBeMocked() { Dummy dummy = RequestStaticInjectionA.DUMMY; assertFalse(mockingDetails(dummy).isMock()); assertNotNull(dummy); } @Test public void dummyShouldBeMocked() { Dummy dummy = RequestStaticInjectionB.DUMMY; assertTrue(mockingDetails(dummy).isMock()); } } ================================================ FILE: jukito/src/test/java/org/jukito/RespectProvidesAnnotationInModuleTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import static org.mockito.Mockito.verify; /** * Test proving that factory methods are called when defined in external module * and installed in JukitoModule. */ @RunWith(JukitoRunner.class) public class RespectProvidesAnnotationInModuleTest { @Test public void shouldRespectProvidesAnnotationUsedInModule(SomeTestClass someTestClass) throws Exception { //-------------------- GIVEN ------------------------------------------------------------------- //-------------------- WHEN -------------------------------------------------------------------- //-------------------- THEN -------------------------------------------------------------------- // injected object should be created by factory method // defined in custom module ModuleWithProvidesMethods. // Init method should be called from factory method verify(someTestClass).someInitMethod(); } /** * Guice test module. */ public static class A extends JukitoModule { @Override protected void configureTest() { install(new ModuleWithProvidesMethods()); } } } ================================================ FILE: jukito/src/test/java/org/jukito/RespectTestScopeWhenUsingAbstractModuleTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import com.google.inject.Inject; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; /** * Test for respecting {@literal @}{@link org.jukito.TestSingleton} * when user modules subclass AbstractModule. */ @RunWith(JukitoRunner.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RespectTestScopeWhenUsingAbstractModuleTest { @Inject SomeTestClass someTestClassOne; @Inject SomeTestClass someTestClassTwo; @Test public void shouldRespectTestSingletonAnnotationA() throws Exception { //-------------------- GIVEN ------------------------------------------------------------------- //-------------------- WHEN -------------------------------------------------------------------- // calls for purpose of test shouldRespectTestSingletonsB someTestClassOne.crazyMethod(); someTestClassOne.crazyMethod(); someTestClassOne.crazyMethod(); //-------------------- THEN -------------------------------------------------------------------- assertEquals(someTestClassOne, someTestClassTwo); } @Test public void shouldRespectTestSingletonsB() throws Exception { //-------------------- GIVEN ------------------------------------------------------------------- //-------------------- WHEN -------------------------------------------------------------------- someTestClassOne.crazyMethod(); //-------------------- THEN -------------------------------------------------------------------- // verify if mock has been reset and thus only one call is registered verify(someTestClassOne, times(1)).crazyMethod(); } @Test public void shouldRespectTestSingletonsC() throws Exception { //-------------------- GIVEN ------------------------------------------------------------------- //-------------------- WHEN -------------------------------------------------------------------- someTestClassOne.crazyMethod(); someTestClassTwo.crazyMethod(); //-------------------- THEN -------------------------------------------------------------------- verify(someTestClassOne, times(2)).crazyMethod(); } /** * Guice test module. */ public static class A extends JukitoModule { @Override protected void configureTest() { install(new ModuleWithProvidesMethods()); } } } ================================================ FILE: jukito/src/test/java/org/jukito/SampleParentTestClassWithInnerTestModule.java ================================================ /* * Copyright 2017 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; /** * Sample Parent Test Class which binds 2 string instances for use by * the {@link ParentClassInnerClassModuleDiscoveryTest}. */ public class SampleParentTestClassWithInnerTestModule { /** * Sample JukitoModule which binds 2 String instances. * The Instances will be injected to an {@code @All} test and counted to verify that * this module is discovered by the JukitoRunner. */ public static final class MyModule extends JukitoModule { @Override protected void configureTest() { bindManyInstances(String.class, "Hello", "World"); } } } ================================================ FILE: jukito/src/test/java/org/jukito/SingletonTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.util.HashMap; import java.util.Map; import org.junit.AfterClass; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that the various flavours of singletons work correctly. */ @RunWith(JukitoRunner.class) public class SingletonTest { /** * Guice test module. */ static class Module extends JukitoModule { @Override protected void configureTest() { bind(MyEagerSingleton.class).asEagerSingleton(); bindMock(MyTestMockSingletonBoundNonMock.class); bind(MyTestEagerSingleton.class); } } @TestSingleton static class Registry { public Map, Integer> registrationCount = new HashMap, Integer>(); public void register(Class clazz) { registrationCount.put(clazz, getCount(clazz) + 1); } public int getCount(Class clazz) { Integer value = registrationCount.get(clazz); if (value == null) { return 0; } return value; } } /** * This class keeps track of what happens in all the tests run in this * class. It's used to make sure all expected tests are called. */ private static class Bookkeeper { static int numberOfTimesTestEagerSingletonIsInstantiated; static int numberOfTimesTestSingletonIsInstantiated; static int numberOfTimesEagerSingletonIsInstantiated; static ExternalSingleton singleton1; static ExternalSingleton singleton2; } /** * This should be instantiated once for the entire test class. */ static class MyEagerSingleton { @Inject MyEagerSingleton(Registry registry) { registry.register(getClass()); Bookkeeper.numberOfTimesEagerSingletonIsInstantiated++; } } /** * This should automatically register before each test. */ @TestEagerSingleton static class MyTestEagerSingleton { @Inject MyTestEagerSingleton(Registry registry) { registry.register(getClass()); Bookkeeper.numberOfTimesTestEagerSingletonIsInstantiated++; } } /** * This should register only in tests where it is injected. */ @TestSingleton static class MyTestSingleton { @Inject MyTestSingleton(Registry registry) { registry.register(getClass()); Bookkeeper.numberOfTimesTestSingletonIsInstantiated++; } } /** * This should be different from one test to the next. */ @TestMockSingleton interface MyTestMockSingleton { void dummy(); } /** * This should be bound as non-mock even though there is an annotation, * because the module explicitely binds it. */ @TestMockSingleton interface MyTestMockSingletonBoundNonMock { void dummy(); } @Inject Registry registry; @Test public void onlyEagerSingletonShouldBeRegistered() { assertEquals(1, registry.getCount(MyTestEagerSingleton.class)); } @Test public void bothSingletonsShouldBeRegistered(MyTestSingleton myTestSingleton) { assertEquals(1, registry.getCount(MyTestEagerSingleton.class)); assertEquals(1, registry.getCount(MyTestSingleton.class)); } @Test public void injectionOfMockShouldBeADifferentObject1(MyTestMockSingleton myTestMockSingleton) { myTestMockSingleton.dummy(); verify(myTestMockSingleton).dummy(); } @Test public void injectionOfMockShouldBeADifferentObject2(MyTestMockSingleton myTestMockSingleton) { myTestMockSingleton.dummy(); verify(myTestMockSingleton).dummy(); } @Test public void injectionOfSingletonMockExplicitelyBoundAsNonSingleton( MyTestMockSingletonBoundNonMock a, MyTestMockSingletonBoundNonMock b) { verify(a, never()).dummy(); verify(b, never()).dummy(); assertNotSame(a, b); } @Test public void firstInjectionOfSingleton(ExternalSingleton obj) { Bookkeeper.singleton1 = obj; } @Test public void secondInjectionOfSingleton(ExternalSingleton obj) { Bookkeeper.singleton2 = obj; } @AfterClass public static void verifyNumberOfInstantiations() { assertEquals(7, Bookkeeper.numberOfTimesTestEagerSingletonIsInstantiated); assertEquals(1, Bookkeeper.numberOfTimesTestSingletonIsInstantiated); assertEquals(1, Bookkeeper.numberOfTimesEagerSingletonIsInstantiated); assertNotSame(Bookkeeper.singleton1, Bookkeeper.singleton2); } } ================================================ FILE: jukito/src/test/java/org/jukito/SomeCoreComponent.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; /** * Sample core component under test in different environments. */ public class SomeCoreComponent { private EnvironmentDependentComponent someComponent; public SomeCoreComponent(EnvironmentDependentComponent someComponent) { this.someComponent = someComponent; } public void run() { someComponent.hello(); } } ================================================ FILE: jukito/src/test/java/org/jukito/SomeTestClass.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; /** * Sample class doing totally nothing. */ public class SomeTestClass { public void someInitMethod() { // nothing } public void crazyMethod() { // nothing special here } } ================================================ FILE: jukito/src/test/java/org/jukito/TestTestDescriptions.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; /** * Simple test with @Description in place. */ @RunWith(JukitoRunner.class) public class TestTestDescriptions { @Test @Description("some nice test description") public void testA() throws Exception { // Given // When // Then } @Test @Description("some nice ultra long test description, some nice ultra long test description," + "some nice ultra long test description, some nice ultra long test description") public void testB() throws Exception { // Given // When // Then } @Test public void testWithoutDescription() throws Exception { // Given // When // Then } } ================================================ FILE: jukito/src/test/java/org/jukito/TransitiveDependencyTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.name.Named; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Test that various form of automatic discovery of transitive dependencies work. */ @RunWith(JukitoRunner.class) public class TransitiveDependencyTest { static class MyModule extends JukitoModule { @Override protected void configureTest() { bind(MyInterface.class).to(MyInterfaceImpl.class).in(TestSingleton.class); bind(MyInterfaceImpl.class); } } interface SubCollaborator { void subCollaborate(); } @TestEagerSingleton static class Collaborator { private final SubCollaborator subCollaborator; @Inject Collaborator(SubCollaborator subCollaborator) { this.subCollaborator = subCollaborator; } } @TestEagerSingleton static class Leader { private final Collaborator collaborator; @Inject Leader(Collaborator collaborator) { this.collaborator = collaborator; } } interface MyInterface { int getValue(); } static class MyDependency { public int getValue() { return 10; } } interface MyDependentInterface { } static class MyInterfaceImpl implements MyInterface { private final MyDependency myDependency; @Inject MyInterfaceImpl(MyDependency myDependency, MyDependentInterface myDependentInterface) { this.myDependency = myDependency; } @Override public int getValue() { return myDependency.getValue(); } } enum MyEnum { OPTION_1, OPTION_2 } static class MyClassInjectedWithUnboundConstants { @Inject @Named("version") Integer version; @Inject @Named("someClass") Class someClass; @Inject @Named("timestamp") Long timestamp; @Inject @Named("option") MyEnum option; @Inject MyClassInjectedWithUnboundConstants( @Named("pi") double pi, @Named("salt") String salt, @Named("small") short small, @Named("tiny") byte tiny, @Named("letter") Character letter) { } @Inject void setAutoinit(@Named("autoinit") boolean autoinit) { } @Inject void setSensitivity(@Named("sensitivity") float sensitivity) { } } @Test public void testDoubleDependency(Leader leader) { verify(leader.collaborator.subCollaborator, never()).subCollaborate(); } @Test public void testDependencyFromInterface(MyInterface myInterface) { assertEquals(10, myInterface.getValue()); } @Test public void testDependencyOnUnboundConstants(MyClassInjectedWithUnboundConstants object) { assertNotNull(object); } } ================================================ FILE: jukito/src/test/java/org/jukito/UseModulesTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import org.jukito.UseModulesTest.Abc; import org.jukito.UseModulesTest.AbcImpl; import org.jukito.UseModulesTest.Def; import org.jukito.UseModulesTest.DefImpl; import org.jukito.UseModulesTest.Klm; import org.jukito.UseModulesTest.KlmImpl; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import com.google.inject.AbstractModule; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** * Test to check that method injection works fine with external modules. */ @RunWith(JukitoRunner.class) @UseModules({AbcModule.class, DefModule.class}) public class UseModulesTest extends UseModulesTestBase { interface Abc { } interface Def { } interface Ghj { } interface Klm { } static class AbcImpl implements Abc { } static class DefImpl implements Def { } static class AbcImpl2 implements Abc { } static class DefImpl2 implements Def { } static class KlmImpl implements Klm { } @Test @UseModules(XyzModule.class) public void testInjectionUsingMethodModules(Abc abc, Def def) { assertTrue(abc instanceof AbcImpl2); assertTrue(def instanceof DefImpl2); } @Test public void testInjectionWithExternalModules(Abc abc, Def def, Klm klm) { assertTrue(abc instanceof AbcImpl); assertTrue(def instanceof DefImpl); assertTrue(klm instanceof KlmImpl); } @Test public void testAutoMockingForMissingBindings(Ghj ghj) { assertNotNull(ghj); assertTrue(Mockito.mockingDetails(ghj).isMock()); } } class XyzModule extends AbstractModule { @Override protected void configure() { bind(Abc.class).to(UseModulesTest.AbcImpl2.class); bind(Def.class).to(UseModulesTest.DefImpl2.class); } } @UseModules({DefModule.class, KlmModule.class}) abstract class UseModulesTestBase { // KlmModule should get installed // DefModule should be ignored because subClass has it } class AbcModule extends AbstractModule { @Override protected void configure() { bind(Abc.class).to(AbcImpl.class); } } class DefModule extends AbstractModule { @Override protected void configure() { bind(Def.class).to(DefImpl.class); } } class KlmModule extends AbstractModule { @Override protected void configure() { bind(Klm.class).to(KlmImpl.class); } } ================================================ FILE: jukito/src/test/java/org/jukito/Value3.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.google.inject.BindingAnnotation; /** * An annotation used in a test class. */ @BindingAnnotation @Retention(RetentionPolicy.RUNTIME) public @interface Value3 { } ================================================ FILE: jukito/src/test/java/org/jukito/environmentdependent/DesktopModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.environmentdependent; import org.jukito.EnvironmentDependentComponent; import com.google.inject.AbstractModule; /** * Sample Environment Dependent Module. */ public class DesktopModule extends AbstractModule { @Override protected void configure() { bind(EnvironmentDependentComponent.class).toInstance(new EnvironmentDependentComponent() { @Override public void hello() { System.err.println("DesktopModule"); } }); } } ================================================ FILE: jukito/src/test/java/org/jukito/environmentdependent/EnvironmentDependentModulesTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.environmentdependent; import org.jukito.EDRunner; import org.jukito.EnvironmentDependentComponent; import org.jukito.EnvironmentDependentModules; import org.jukito.SomeCoreComponent; import org.jukito.UseModules; import org.jukito.environmentdependent.EnvironmentDependentModulesTest.SomeCoreModule; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.AbstractModule; import com.google.inject.Provides; /** * This test is run as many times as many Environment Dependent Modules you declare. * Every Environment Dependent Module is installed in separated Injector * with default core modules you declare in @UseModules. */ @EnvironmentDependentModules({MobileModule.class, DesktopModule.class, TabletModule.class}) @UseModules(SomeCoreModule.class) @RunWith(EDRunner.class) public class EnvironmentDependentModulesTest { @Test public void shouldRunAsManyTimesAsManyInjectorsWereCreated(SomeCoreComponent coreComponent) throws Exception { coreComponent.run(); } /** * SomeCoreModule. */ public static class SomeCoreModule extends AbstractModule { @Provides SomeCoreComponent createCalculator(EnvironmentDependentComponent dependentComponent) { return new SomeCoreComponent(dependentComponent); } @Override protected void configure() { } } } ================================================ FILE: jukito/src/test/java/org/jukito/environmentdependent/MobileModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.environmentdependent; import org.jukito.EnvironmentDependentComponent; import com.google.inject.AbstractModule; /** * Sample Environment Dependent Module. */ public class MobileModule extends AbstractModule { @Override protected void configure() { bind(EnvironmentDependentComponent.class).toInstance(new EnvironmentDependentComponent() { @Override public void hello() { System.err.println("MobileModule"); } }); } } ================================================ FILE: jukito/src/test/java/org/jukito/environmentdependent/TabletModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.environmentdependent; import org.jukito.EnvironmentDependentComponent; import com.google.inject.AbstractModule; /** * Sample Environment Dependent Module. */ public class TabletModule extends AbstractModule { @Override protected void configure() { bind(EnvironmentDependentComponent.class).toInstance(new EnvironmentDependentComponent() { @Override public void hello() { System.err.println("TabletModule"); } }); } } ================================================ FILE: jukito-samples/pom.xml ================================================ 4.0.0 org.jukito jukito-parent 1.6-SNAPSHOT jukito-samples Jukito Samples org.apache.maven.plugins maven-checkstyle-plugin com.google.inject guice org.jukito jukito ${project.version} test ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/Car.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; public abstract class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } public void startEngine() { engine.initiateIgnition(); } public Engine getEngine() { return engine; } } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/DieselEngine.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; public class DieselEngine implements Engine { @Override public void initiateIgnition() { } } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/Engine.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; public interface Engine { void initiateIgnition(); } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/FordMustang.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; import jakarta.inject.Inject; public class FordMustang extends Car { @Inject public FordMustang(Engine engine) { super(engine); } } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/PetrolEngine.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; public class PetrolEngine implements Engine { @Override public void initiateIgnition() { } } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/modules/DieselLineModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples.modules; import org.jukito.samples.DieselEngine; import org.jukito.samples.Engine; import com.google.inject.AbstractModule; public class DieselLineModule extends AbstractModule { @Override protected void configure() { bind(Engine.class).to(DieselEngine.class); } } ================================================ FILE: jukito-samples/src/main/java/org/jukito/samples/modules/PetrolLineModule.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples.modules; import org.jukito.samples.Engine; import org.jukito.samples.PetrolEngine; import com.google.inject.AbstractModule; public class PetrolLineModule extends AbstractModule { @Override protected void configure() { bind(Engine.class).to(PetrolEngine.class); } } ================================================ FILE: jukito-samples/src/test/java/org/jukito/samples/FordMustangTest.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; import org.jukito.JukitoRunner; import org.junit.Test; import org.junit.runner.RunWith; import jakarta.inject.Inject; import static org.mockito.Mockito.verify; /** * A simple test with one mock (engine) and one real object (FordMustang). */ @RunWith(JukitoRunner.class) public class FordMustangTest { @Inject FordMustang sut; @Test public void shouldInitiateIgnitionWhenCarStart() throws Exception { // Given // When sut.startEngine(); // Then verify(sut.getEngine()).initiateIgnition(); } } ================================================ FILE: jukito-samples/src/test/java/org/jukito/samples/FordMustangTest2.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; import org.jukito.JukitoModule; import org.jukito.JukitoRunner; import org.junit.Test; import org.junit.runner.RunWith; import jakarta.inject.Inject; import static org.mockito.Mockito.verify; /** * A simple test with one real DOC (binding in test). */ @RunWith(JukitoRunner.class) public class FordMustangTest2 { @Inject FordMustang sut; @Test public void shouldInitiateIgnitionWhenCarStart() throws Exception { // Given // Then sut.startEngine(); // Then verify(sut.getEngine()).initiateIgnition(); } public static class A extends JukitoModule { @Override protected void configureTest() { // Diesel in Mustang, yeaah I know :) bind(Engine.class).to(DieselEngine.class); // necessary if you want to verify interaction on real object bindSpy(DieselEngine.class); } } } ================================================ FILE: jukito-samples/src/test/java/org/jukito/samples/FordMustangTest3.java ================================================ /** * Copyright 2013 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jukito.samples; import org.jukito.JukitoModule; import org.jukito.JukitoRunner; import org.jukito.samples.modules.DieselLineModule; import org.junit.Test; import org.junit.runner.RunWith; import jakarta.inject.Inject; import static org.mockito.Mockito.verify; /** * A simple test with one real DOC (binding via module installation). */ @RunWith(JukitoRunner.class) public class FordMustangTest3 { @Inject FordMustang sut; @Test public void shouldInitiateIgnitionWhenCarStart() throws Exception { // Given // When sut.startEngine(); // Then verify(sut.getEngine()).initiateIgnition(); } /** * JukitoModule. */ public static class A extends JukitoModule { @Override protected void configureTest() { // install yours module as you wish install(new DieselLineModule()); // necessary if you want to verify interaction on real object bindSpy(DieselEngine.class); } } } ================================================ FILE: pom.xml ================================================ 4.0.0 org.sonatype.oss oss-parent 9 org.jukito jukito-parent 1.6-SNAPSHOT pom Jukito 2010 A testing framework with automocking base on JUnit, Guice and Mokito. http://jukito.org Apache 2 http://www.apache.org/licenses/LICENSE-2.0.txt repo A business-friendly OSS license ArcBees Inc. http://arcbees.com Philippe Beaudoin philippe.beaudoin@gmail.com http://www.google.com/profiles/philippe.beaudoin ArcBees http://arcbees.com architect lead developer -8 http://goo.gl/xV2K8 Christian Goudreau goudreau.christian@gmail.com ArcBees http://arcbees.com developer -5 Brandon Donnelson Przemek Galazka Simon-Pierre Gingras Maxime Meriouma-Caron Alden Quimby olafleur Julian Lettner Adam Piper Mike Mansell jclariviere Christopher Viel Jared Martin scm:git:git@github.com:ArcBees/Jukito.git/ scm:git:git@github.com:ArcBees/Jukito.git https://github.com/ArcBees/Jukito GitHub Issues https://github.com/ArcBees/Jukito/issues Team City http://teamcity.gonevertical.org Development jukito+subscribe@googlegroups.com jukito+unsubscribe@googlegroups.com jukito@googlegroups.com http://groups.google.com/group/jukito 11 UTF-8 UTF-8 7.0.0 4.13.2 4.11.0 3.6.0 10.20.1 3.13.0 3.1.3 2.9 3.11.1 3.3.1 3.5.2 1.24 0.12 jukito jukito-samples org.apache.maven.plugins maven-compiler-plugin ${maven-compiler-plugin.version} ${target.jdk} ${target.jdk} ${project.build.sourceEncoding} org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} **/*Test.java **/*TestCase.java org.apache.maven.plugins maven-deploy-plugin ${maven-deploy-plugin.version} org.apache.maven.plugins maven-checkstyle-plugin ${maven-checkstyle-plugin.version} /codequality/checkstyle.xml /codequality/suppressions.xml basedir=${basedir} true true false true validate validate checkstyle com.puppycrawl.tools checkstyle ${checkstyle.version} org.apache.maven.plugins maven-source-plugin ${maven-source-plugin.version} jar org.apache.maven.plugins maven-release-plugin true false release -Psonatype-oss-release -Prelease -Dgpg.passphrase=${gpg.passphrase} org.codehaus.mojo animal-sniffer-maven-plugin ${animal-sniffer-maven-plugin.version} org.codehaus.mojo.signature java15 1.0 process-classes check org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} 2048 true Jukito Javadocs -Xdoclint:none http://download.oracle.com/javase/6/docs/api/ http://google-web-toolkit.googlecode.com/svn/javadoc/latest/ http://google-gin.googlecode.com/svn/trunk/javadoc/ http://google-guice.googlecode.com/svn/trunk/javadoc/ http://aopalliance.sourceforge.net/doc/ https://developers.google.com/appengine/docs/java/javadoc/ http://docs.guava-libraries.googlecode.com/git/javadoc/ ${project.build.directory}/javadoc ${project.reporting.outputDirectory}/javadoc **/*.txt
    Back to Jukito Home ]]>
    com.github.github site-maven-plugin ${github.version} Creating site for ${project.version} github *.DS_Store *.sh options packages true true site site
    org.mockito mockito-core ${mockito.version} junit junit ${junit.version} com.google.inject guice ${guice.version} com.google.inject.extensions guice-assistedinject ${guice.version}