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);
}
}
그리고 내 테스트에서 InterfaceC와 InterfaceB를 그대로 유지하면서 InterfaceC 만 재정의하고 싶습니다. 그래서 다음과 같은 것을 원합니다.
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 매핑이 있으면 잘 작동합니다. 인터페이스와 구현.
또한이를 동료와 논의한 후 전체 모듈을 재정의하고 모듈을 올바르게 정의했는지 확인해야합니다. 바인딩이 모듈에 잘못 배치되어 이동 해야하는 경우 문제가 발생할 수 있으므로 바인딩을 더 이상 재정의 할 수 없으므로 테스트로드가 중단 될 수 있습니다.
이것은 당신이 찾고있는 대답이 아닐 수도 있지만, 단위 테스트를 작성하는 경우 인젝터를 사용하지 말고 손으로 가짜 또는 가짜 물체를 주입해야합니다.
반면에 단일 바인딩을 실제로 바꾸려면 다음을 사용할 수 있습니다 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/...
You can just create a new class ConcreteC
in your test directory using the same package as for your original class. Guice will then bind InterfaceC
to ConcreteC
from your test directory whereas all other interfaces will be bound to your production classes.
You want to use Juckito where you can declare your custom configuration for each test class.
@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();
}
}
In a different setup, we have more than one activity defined in separate modules. The activity that's being injected into is in an Android Library Module, with its own RoboGuice module definition in the AndroidManifest.xml file.
The setup looks like this. In the Library Module there are these definitions:
AndroidManifest.xml:
<application android:allowBackup="true">
<activity android:name="com.example.SomeActivity/>
<meta-data
android:name="roboguice.modules"
android:value="com.example.MainModule" />
</application>
Then we have a type being injected:
interface Foo { }
Some default implementation of Foo:
class FooThing implements Foo { }
MainModule configures the FooThing implementation for Foo:
public class MainModule extends AbstractModule {
@Override
protected void configure() {
bind(Foo.class).to(FooThing.class);
}
}
And finally, an Activity that consumes Foo:
public class SomeActivity extends RoboActivity {
@Inject
private Foo foo;
}
In the consuming Android Application Module, we would like to use SomeActivity
but, for testing purposes, inject our own Foo
.
public class SomeOtherActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(this, SomeActivity.class);
startActivity(intent);
}
}
One might argue to expose the module handling to the client application, however, we need to mostly hide the components being injected because the Library Module is an SDK, and exposing pieces has larger implications.
(Remember, this is for testing, so we know the internals of SomeActivity, and know it consumes a (package visible) Foo).
The way I found that works makes sense; use the the suggested override for testing:
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);
}
}
Now, when SomeActivity
is started, it will get OtherFooThing
for its injected Foo
instance.
It's a very specific situation where, in our case, OtherFooThing was used internally to record test situations, while FooThing was used, by default, for all other uses.
Keep in mind, we are using #newDefaultRoboModule
in our unit tests, and it works flawlessly.
참고URL : https://stackoverflow.com/questions/483087/overriding-binding-in-guice
'IT' 카테고리의 다른 글
Huawei 전화의 "보호 된 앱"설정 및 처리 방법 (0) | 2020.07.04 |
---|---|
PostgreSQL로 데이터베이스 간 쿼리를 수행 할 수 있습니까? (0) | 2020.07.04 |
git push -u origin master에서 -u 플래그는 무엇을 의미합니까? (0) | 2020.07.04 |
이 예제에서“엄격한 사용”이 성능 10 배를 향상시키는 이유는 무엇입니까? (0) | 2020.07.04 |
Xcode 4-콘솔 / 로그 창 분리 (0) | 2020.07.04 |