programing

Guice 바인딩 덮어쓰기

prostudy 2022. 7. 4. 21:46
반응형

Guice 바인딩 덮어쓰기

이제 막 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);
    }
}

또, 테스트에서는, 인터페이스 A와 인터페이스 B를 tact로 유지하면서, 인터페이스 C만을 오버라이드 하고 싶다고 생각하고 있습니다.따라서 다음과 같은 것을 원합니다.

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 태그를 사용하여 테스트 케이스에 바인딩을 제공하기만 하면 원하는 것을 달성할 수 있을 것 같습니다.이것은 인터페이스와 실장 사이에 1-1의 매핑이 있는 경우에 유효하게 동작합니다.

또한 이 문제에 대해 동료와 논의한 결과 모듈 전체를 덮어쓰고 모듈을 올바르게 정의해야 할 것으로 보입니다.이로 인해 바인딩이 모듈 내에서 잘못 배치되어 이동해야 하는 문제가 발생할 수 있습니다.따라서 바인딩을 덮어쓸 수 없게 되어 테스트 부하가 중단될 수 있습니다.

이것은 여러분이 찾고 있는 답이 아닐 수도 있지만, 만약 여러분이 단위 테스트를 쓰고 있다면, 여러분은 아마도 주입기를 사용하지 말고 손으로 모의 또는 가짜 물체를 주입해야 할 것입니다.

한편, 1개의 바인딩을 정말로 교환하고 싶은 경우는,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());

프로덕션 모듈을 변경하지 않고 다음과 같은 기본 메이브와 같은 프로젝트 구조를 사용하는 경우

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

새 클래스를 만들면 됩니다.ConcreteC테스트 디렉토리에서 원래 클래스와 동일한 패키지를 사용합니다.는 기스를 .InterfaceC로로 합니다.ConcreteC다른 인터페이스는 모두 프로덕션 클래스에 바인딩됩니다.

각 테스트 클래스에 대한 사용자 지정 구성을 선언할 수 있는 Juckito를 사용하려고 합니다.

@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();
    }
}

다른 설정에서는 다른 모듈에 정의된 액티비티가 여러 개 있습니다.삽입되는 액티비티는 AndroidManifest.xml 파일에 자체 RoboGuice 모듈 정의와 함께 Android Library Module에 있습니다.

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

Android Manifest.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 { }

Main Module은 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 에서는 「Android 어플리케이션 모듈」을 사용하고 하고 있습니다.SomeActivity 주사, 우리만의 시험용 주사, 우리만의 시험용 주사, 시험용 주사, 시험용 주사, 시험용 주사, 시험용 주사, 시험용 주사.Foo.

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

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

모듈 처리를 클라이언트애플리케이션에 공개해야 한다고 주장할 수도 있지만 Library Module은 SDK이기 때문에 삽입되는 컴포넌트를 대부분 숨길 필요가 있습니다.또한 조각 공개는 더 큰 의미를 가집니다.

(이것은 테스트용이므로 Some Activity의 내부 정보를 알고 있으며, (패키지 표시) 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★★★★★★ 。

이 경우 테스트 상황을 기록하기 위해 OtherFooThing이 내부적으로 사용되었으며 FooThing은 기본적으로 다른 모든 용도로 사용되었습니다.

주의해 주세요.#newDefaultRoboModule완벽하게 작동합니다.

언급URL : https://stackoverflow.com/questions/483087/overriding-binding-in-guice

반응형