Skip to content

[Needle] Handle circular dependencies #853

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,21 @@ public <T> T getInstance(final Class<T> type) {
@Override
public void start() {
logger.trace("start()");
for (final Class<?> stepDefinitionType : cachedStepsInstances.keySet()) {
cachedStepsInstances.put(stepDefinitionType, createStepsInstance(stepDefinitionType));
try {
// First create all instances
for (final Class<?> stepDefinitionType : cachedStepsInstances.keySet()) {
cachedStepsInstances.put(stepDefinitionType, createStepsInstance(stepDefinitionType));
}
// Then collect injection providers from all instances
for (Object stepsInstance : cachedStepsInstances.values()) {
addInjectionProvider(collectInjectionProvidersFromStepsInstance.apply(stepsInstance));
}
// Now init all instances, having the injection providers from all other instances available
for (Object stepsInstance : cachedStepsInstances.values()) {
initTestcase(stepsInstance);
}
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}

Expand Down Expand Up @@ -78,16 +91,9 @@ private <T> T nullSafeGetInstance(final Class<T> type) {
return (T) instance;
}

private <T> T createStepsInstance(final Class<T> type) {
private <T> T createStepsInstance(final Class<T> type) throws Exception {
logger.trace("createInstance(): " + type.getCanonicalName());
try {
final T stepsInstance = createInstanceByDefaultConstructor.apply(type);
addInjectionProvider(collectInjectionProvidersFromStepsInstance.apply(stepsInstance));
initTestcase(stepsInstance);
return stepsInstance;
} catch (final Exception e) {
throw new IllegalStateException(e);
}
return createInstanceByDefaultConstructor.apply(type);
}

static InjectionProvider<?>[] setUpInjectionProviders(final String resourceName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
package cucumber.runtime.java.needle.test;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

import javax.inject.Inject;

import org.hamcrest.core.Is;

import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import cucumber.api.needle.InjectionProviderInstancesSupplier;
import cucumber.api.needle.NeedleInjectionProvider;
import cucumber.runtime.java.needle.injection.DefaultInstanceInjectionProvider;
import cucumber.runtime.java.needle.test.atm.AtmService;
import cucumber.runtime.java.needle.test.atm.AtmServiceBean;
import cucumber.runtime.java.needle.test.atm.BicGetter;
import cucumber.runtime.java.needle.test.injectionprovider.ValueInjectionProvider;
import de.akquinet.jbosscc.needle.annotation.ObjectUnderTest;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;
import org.hamcrest.core.Is;

import javax.inject.Inject;

import java.util.Collections;
import java.util.Set;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

public class AtmWithdrawalSteps {

Expand All @@ -31,12 +35,23 @@ public class AtmWithdrawalSteps {
@Inject
private BicGetter bicGetter;

@Inject
private MoreSteps moreSteps;

/*
* Provider instance will be added dynamically.
*/
@NeedleInjectionProvider
private final InjectionProvider<?> valueProvider = new ValueInjectionProvider(VALUE);

@NeedleInjectionProvider
private final InjectionProviderInstancesSupplier thisInjectionProviderSupplier = new InjectionProviderInstancesSupplier() {
@Override
public Set<InjectionProvider<?>> get() {
return Collections.<InjectionProvider<?>>singleton(new DefaultInstanceInjectionProvider<AtmWithdrawalSteps>(AtmWithdrawalSteps.this));
}
};

/*
* This is what we test
*/
Expand Down Expand Up @@ -65,4 +80,12 @@ public void I_have_EUR_remaining(final int remaining) throws Throwable {
assertThat(atmService.getAmount(), Is.is(remaining));
}

@Before
public void checkInjectionWorked() {
assertTrue("Got a mock injected instead of the real instance.", moreSteps.isThisReallyYouOrJustAMock());
}

public boolean isThisReallyYouOrJustAMock() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cucumber.runtime.java.needle.test;

import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.needle.NeedleInjectionProvider;
import cucumber.runtime.java.needle.injection.DefaultInstanceInjectionProvider;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;

import javax.inject.Inject;

import static org.junit.Assert.assertTrue;

/**
* Just here to show that injection providers from this class also work in other classes.
*
* @author Lars Bilger
*/
public class MoreSteps {

@NeedleInjectionProvider
private InjectionProvider<MoreSteps> thisInjectionProvider = new DefaultInstanceInjectionProvider<MoreSteps>(this);

@Inject
private AtmWithdrawalSteps atmWithdrawalSteps;

@Before
public void checkInjectionWorked() {
assertTrue("Got a mock injected instead of the real instance.", atmWithdrawalSteps.isThisReallyYouOrJustAMock());
}

@Given("^i call a step that i don't really need$")
public void this_step_is_here_only_to_have_the_class_instantiated() {
}

public boolean isThisReallyYouOrJustAMock() {
return true;
}
}