3

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!

  • are you sure that ThreadWeaver is respecting your `@Before` method? From what I can tell there is no `@Before` in ThreadWeaver, and JUnit only respects annotations like `@Before` and `@After` on the TestCase implementation itself --not classes created by or used by a test case. Maybe its best to put it in the `@ThreadedBefore` method? – Groostav Dec 29 '15 at 18:36

1 Answers1

2

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.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thanks to the both of you! – Navalorange Dec 29 '15 at 23:17
  • I realize the second thread is important for a sane test, I just wanted to make sure I could get that far before putting that effort in. That makes perfect sense, and I ended up just setting up calling `setupComponents()` in the `@ThreadedBefore` method just like Groostav said. I ended up running into another problem with javaFX which I thought was the same issue, but when I finally took the time to look at the stack trace I found I was out of the woods. Thanks for the help! Looks like it was something simple after all. I'll be sure to remember to upvote your answer when I get 15 rep! – Navalorange Dec 29 '15 at 23:26