Use Guice to create components to use with ThreadWeaver

140 Views Asked by At

The application I have been working on has been getting more and more complicated, and it's gotten to the point where I have been running into the same problems over and over again with concurrency. It no longer made any sense to solve the same problems and not have any regression tests.

That's when I found ThreadWeaver. It was really nice for some simple concurrency cases I cooked up, but I started to get frustrated when trying to do some more complicated cases with my production code. Specifically, when injecting components using Guice.

I've had a bit of a hard time understanding the implications of the way ThreadWeaver runs tests, and looked for any mention of Guice or DI in the wiki documents, but with no luck.

Is Guice compatible with ThreadWeaver?

Here is my test

@Test
public void concurrency_test() {
    AnnotatedTestRunner runner = new AnnotatedTestRunner();
    runner.runTests(OPYLWeaverImpl.class, OPYLSurrogateTranscodingService.class);
}

Here is my test implementation

public class OPYLWeaverImpl extends WeaverFixtureBase {

@Inject private TaskExecutor                 taskExecutor;
@Inject private Serializer                   serializer;
@Inject private CountingObjectFileMarshaller liveFileMarshaller;
@Inject private GraphModel                   graphModel;
@Inject private CountingModelUpdaterService  updaterService;
@Inject private BabelCompiler                babelCompiler;
@Inject private EventBus                     eventBus;

OPYLSurrogateTranscodingService service;

private Path testPath;

@ThreadedBefore
public void before() {
    service = new OPYLSurrogateTranscodingService(eventBus, taskExecutor, serializer, liveFileMarshaller,
            () -> new OPYLSurrogateTranscodingService.Importer(graphModel, babelCompiler, updaterService, eventBus),
            () -> new OPYLSurrogateTranscodingService.Validator(eventBus, babelCompiler),
            () -> new OPYLSurrogateTranscodingService.Exporter(graphModel, updaterService));
}

@ThreadedMain
public void mainThread() {
    testPath = FilePathOf.OASIS.resolve("Samples/fake-powershell-unit-test.opyl");
    service.applyToExistingGraphModel(testPath);
}

@ThreadedSecondary
public void secondaryThread() {

}

@ThreadedAfter
public void after() {

}

And the WeaverFixtureBase

public class WeaverFixtureBase {
@Inject protected CountingEventBus eventBus;

@Before public final void setupComponents() {
    Injector injector = Guice.createInjector(new WeaverTestingEnvironmentModule(CommonSerializationBootstrapper.class));
    injector.getMembersInjector((Class) this.getClass()).injectMembers(this);
}
private class WeaverTestingEnvironmentModule extends AbstractModule {

    private final Class<? extends SerializationBootstrapper> serializationBootstrapper;

    public WeaverTestingEnvironmentModule(Class<? extends SerializationBootstrapper> serializationConfiguration) {
        serializationBootstrapper = serializationConfiguration;
    }

    @Override protected void configure() {
        bind(TaskExecutor.class).to(FakeSerialTaskExecutor.class);
        bind(SerializationBootstrapper.class).to(serializationBootstrapper);
        bind(ModelUpdaterService.class).toInstance(new CountingModelUpdaterService());
        bindFactory(StaticSerializationConfiguration.Factory.class);

        CountingEventBus localEventBus = new CountingEventBus();

        bind(Key.get(EventBus.class, Bindings.GlobalEventBus.class)).toInstance(localEventBus);
        bind(Key.get(EventBus.class, Bindings.LocalEventBus.class)).toInstance(localEventBus);
        bind(CountingEventBus.class).toInstance(localEventBus);
        bind(EventBus.class).toInstance(localEventBus);

    }
    @Provides
    @Singleton
    public GraphModel getGraphModel(EventBus eventBus, Serializer serializer) {
        return MockitoUtilities.createMockAsInterceptorTo(new GraphModel(eventBus, serializer));
    }
}

But when the classloader loads OPYLWeaverImpl, none of the Guice stuff goes off and I get a big pile of nulls.

I feel like this is one of those "missing-something-really-simple" kind of scenarios. Sorry if it is!

1

There are 1 best solutions below

2
On

The above comment is right. Thread-weaver is fully agnostic of JUnit. Thread weaver is its own runner that executes a test case respecting its own annotations. You must not use any JUnit-specific annotation within a Thread Weaver test.

Other than that, Thread Weaver does not need any compatibility for a specific framework. It manipulates Java byte code and loads that manipulated code using aeperate class loaders.

Finally, a Thread Weaver test without any secondary test does not make any sense. Thread weaver works by interleaving seperate execution paths. Without a second thread, Thread Weaver only steps through a single thread without adding any value.