문제

방금 Guice와 함께 연주를 시작했고, 내가 생각할 수있는 사용 사례는 테스트에서 단일 바인딩을 무시하고 싶다는 것입니다. 나머지 생산 수준 바인딩을 사용하여 모든 것이 올바르게 설정되고 복제를 피하기 위해 원합니다.

그러니 다음 모듈이 있다고 상상해보십시오

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}

그리고 내 시험에서 나는 계면과 인터페이스를 보관하면서 인터페이스를 무시하고 싶다. 그래서 나는 다음과 같은 것을 원한다.

Module testModule = new Module() {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(new ProductionModule(), testModule);

나는 또한 운이없는 다음을 시도했습니다.

Module testModule = new ProductionModule() {
    public void configure(Binder binder) {
        super.configure(binder);
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(testModule);

내가 원하는 것을 할 수 있는지 또는 내가 잘못된 나무를 완전히 짖는 것인지 아는 사람이 있습니까?

--- 후속 조치 : 인터페이스에서 @implementedby 태그를 사용하고 테스트 케이스에 바인딩을 제공하면 원하는 것을 달성 할 수있는 것 같습니다. 인터페이스 및 구현.

또한, 동료와 이것을 논의한 후에 우리는 전체 모듈을 무시하고 모듈을 올바르게 정의하는 길을 향한 길을 향한 것 같습니다. 이는 모듈에 바인딩이 잘못 배치되어 이동 해야하는 경우 문제를 일으킬 수있는 것처럼 보이므로 바인딩이 더 이상 재정의 될 수 없으므로 수많은 테스트를 중단 할 수 있습니다.

도움이 되었습니까?

해결책

이것은 당신이 찾고있는 답이 아닐 수도 있지만, 단위 테스트를 작성하는 경우 인젝터를 사용하지 않아야하고 오히려 손으로 모의 또는 가짜 물건을 주입해서는 안됩니다.

반면에 단일 바인딩을 실제로 교체하려면 사용할 수 있습니다. Modules.override(..):

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}
public class TestModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}
Guice.createInjector(Modules.override(new ProductionModule()).with(new TestModule()));

자세히보다 여기.

그러나 Javadoc로 Modules.overrides(..) 권장합니다. 바인딩을 무시할 필요가없는 방식으로 모듈을 설계해야합니다. 당신이 준 예에서, 당신은 InterfaceC 별도의 모듈로.

다른 팁

상속을 사용하지 않는 이유는 무엇입니까? 특정 바인딩을 무시할 수 있습니다 overrideMe 공유 구현을 남기는 방법 configure 방법.

public class DevModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(TestDevImplA.class);
        overrideMe(binder);
    }

    protected void overrideMe(Binder binder){
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
};

public class TestModule extends DevModule {
    @Override
    public void overrideMe(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}

마지막으로 인젝터를 이런 식으로 만듭니다.

Guice.createInjector(new TestModule());

생산 모듈을 변경하고 싶지 않은 경우 기본 Maven과 같은 프로젝트 구조가있는 경우

src/test/java/...
src/main/java/...

새 클래스 만 만들 수 있습니다 ConcreteC 원래 클래스와 동일한 패키지를 사용하는 테스트 디렉토리에서. 그런 다음 Guice는 묶을 것입니다 InterfaceC 에게 ConcreteC 테스트 디렉토리에서 다른 모든 인터페이스는 프로덕션 클래스에 바인딩됩니다.

당신은 사용하고 싶습니다 주키 각 테스트 클래스에 대한 사용자 정의 구성을 선언 할 수있는 곳.

@RunWith(JukitoRunner.class)
class LogicTest {
    public static class Module extends JukitoModule {

        @Override
        protected void configureTest() {
            bind(InterfaceC.class).to(MockC.class);
        }
    }

    @Inject
    private InterfaceC logic;

    @Test
    public testLogicUsingMock() {
        logic.foo();
    }
}

다른 설정에는 별도의 모듈로 둘 이상의 활동이 정의되어 있습니다. 주입되는 활동은 Android Manifest.xml 파일의 자체 Roboguice 모듈 정의와 함께 Android 라이브러리 모듈에 있습니다.

설정은 다음과 같습니다. 라이브러리 모듈에는 다음과 같은 정의가 있습니다.

AndroidManifest.xml :

<application android:allowBackup="true">
    <activity android:name="com.example.SomeActivity/>
    <meta-data
        android:name="roboguice.modules"
        android:value="com.example.MainModule" />
</application>

그런 다음 유형이 주입됩니다.

interface Foo { }

FOO의 일부 기본 구현 :

class FooThing implements Foo { }

MainModule은 FOO에 대한 Foothing 구현을 구성합니다.

public class MainModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Foo.class).to(FooThing.class);
    }
}

마지막으로 Foo를 소비하는 활동 :

public class SomeActivity extends RoboActivity {
    @Inject
    private Foo foo;
}

소비 Android 애플리케이션 모듈에서 사용하고 싶습니다. SomeActivity 그러나 테스트 목적으로 우리 자신을 주입하십시오 Foo.

public class SomeOtherActivity extends Activity {
    @Override
    protected void onResume() {
        super.onResume();

        Intent intent = new Intent(this, SomeActivity.class);
        startActivity(intent);
    }
}

모듈 처리를 클라이언트 애플리케이션에 노출시키기 위해 주장 할 수도 있지만, 라이브러리 모듈이 SDK이기 때문에 주입되는 구성 요소를 대부분 숨겨야하며, 노출 조각은 더 큰 영향을 미칩니다.

(이것은 테스트를위한 것이므로, 우리는 Someactivity의 내부를 알고 있으며, 그것이 (패키지 가시적) foo를 소비한다는 것을 알고 있습니다).

내가 그 일을 발견 한 방식은 의미가 있습니다. 제안 된 재정의를 사용하십시오 테스트:

public class SomeOtherActivity extends Activity {
    private class OverrideModule
            extends AbstractModule {

        @Override
        protected void configure() {
            bind(Foo.class).to(OtherFooThing.class);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RoboGuice.overrideApplicationInjector(
                getApplication(),
                RoboGuice.newDefaultRoboModule(getApplication()),
                Modules
                        .override(new MainModule())
                        .with(new OverrideModule()));
    }

    @Override
    protected void onResume() {
        super.onResume();

        Intent intent = new Intent(this, SomeActivity.class);
        startActivity(intent);
    }
}

이제 언제 SomeActivity 시작되면 얻을 것입니다 OtherFooThing 주사를 위해 Foo 사례.

우리의 경우 우리의 경우 다른 모든 용도로 기본적으로 다른 모든 용도를 위해 산기도를 사용하는 반면, 다른 모든 용도는 테스트 상황을 기록하는 데 내부적으로 사용되는 매우 구체적인 상황입니다.

명심하십시오 ~이다 사용 #newDefaultRoboModule 우리의 단위 테스트에서는 완벽하게 작동합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top