/* * Copyright 2014 Google Inc. All rights reserved. * * 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 com.google.acai; import static com.google.common.truth.Truth.assertThat; import com.google.inject.AbstractModule; import com.google.inject.Provider; import com.google.inject.ProvisionException; import java.util.concurrent.CountDownLatch; import javax.inject.Inject; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class TestScopeTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Mock private Statement statement; @Mock private FrameworkMethod frameworkMethod; @Test public void sameInstanceInjectedWithinTest() throws Throwable { FakeTestClass test = new FakeTestClass(); new Acai(EmptyTestModule.class).apply(statement, frameworkMethod, test).evaluate(); assertThat(test.instanceOne).isNotNull(); assertThat(test.instanceTwo).isSameAs(test.instanceOne); } @Test public void differentInstanceInjectedAcrossTests() throws Throwable { FakeTestClass testOne = new FakeTestClass(); FakeTestClass testTwo = new FakeTestClass(); new Acai(EmptyTestModule.class).apply(statement, frameworkMethod, testOne).evaluate(); new Acai(EmptyTestModule.class).apply(statement, frameworkMethod, testTwo).evaluate(); assertThat(testOne.instanceOne).isNotSameAs(testTwo.instanceOne); } @Test public void servicesInstantiatedOutsideTestScope() throws Throwable { FakeTestClass test = new FakeTestClass(); thrown.expect(ProvisionException.class); thrown.expectMessage("@TestScoped binding outside test"); new Acai(InvalidTestModule.class).apply(statement, frameworkMethod, test).evaluate(); } @Test public void canCallProviderInServiceSetupAndTeardown() throws Throwable { FakeTestClass test = new FakeTestClass(); new Acai(ValidTestModule.class).apply(statement, frameworkMethod, test).evaluate(); assertThat(ValidTestingService.valueFromBeforeTest).isNotNull(); assertThat(ValidTestingService.valueFromAfterTest) .isSameAs(ValidTestingService.valueFromBeforeTest); } @Test public void parallelTestsReceiveDifferentInstances() throws Throwable { final FakeTestClass testOne = new FakeTestClass(); FakeTestClass testTwo = new FakeTestClass(); final CountDownLatch testStarted = new CountDownLatch(1); final CountDownLatch endTest = new CountDownLatch(1); Thread testOneThread = new Thread( () -> { try { new Acai(EmptyTestModule.class) .apply( new Statement() { @Override public void evaluate() throws Throwable { testStarted.countDown(); endTest.await(); } }, frameworkMethod, testOne) .evaluate(); } catch (Throwable throwable) { throw new RuntimeException(throwable); } }); testOneThread.start(); // Wait for test one to be running. testStarted.await(); new Acai(EmptyTestModule.class).apply(statement, frameworkMethod, testTwo).evaluate(); // Allow test one to complete now that testTwo has run in parallel. endTest.countDown(); testOneThread.join(); assertThat(testOne.instanceOne).isNotNull(); assertThat(testOne.instanceOne).isNotNull(); assertThat(testOne.instanceOne).isNotSameAs(testTwo.instanceOne); } private static class EmptyTestModule extends AbstractModule { @Override protected void configure() { // No-op. } } private static class InvalidTestModule extends TestingServiceModule { @Override protected void configureTestingServices() { bindTestingService(InvalidTestingService.class); } } private static class ValidTestModule extends TestingServiceModule { @Override protected void configureTestingServices() { bindTestingService(ValidTestingService.class); } } private static class FakeTestClass { @Inject MyTestScopedClass instanceOne; @Inject MyTestScopedClass instanceTwo; } @TestScoped private static class MyTestScopedClass {} private static class InvalidTestingService implements TestingService { @Inject MyTestScopedClass testScoped; } private static class ValidTestingService implements TestingService { @Inject Provider<MyTestScopedClass> testScoped; static MyTestScopedClass valueFromBeforeTest; static MyTestScopedClass valueFromAfterTest; @BeforeTest void beforeTest() { valueFromBeforeTest = testScoped.get(); } @AfterTest void afterTest() { valueFromAfterTest = testScoped.get(); } } }