গুইসে ওভাররাইডিং বাইন্ডিং


138

আমি সবেমাত্র গুইসের সাথে খেলতে শুরু করেছি এবং এমন একটি ব্যবহারের ক্ষেত্রে যা আমি ভাবতে পারি তা হ'ল একটি পরীক্ষায় আমি কেবল একটি একক বাঁধাইকে ওভাররাইড করতে চাই। আমার মনে হয় যে সবকিছু সঠিকভাবে সেট আপ হয়েছে এবং নকলটি এড়ানোর জন্য আমি বাকি উত্পাদন স্তরের বাইন্ডিংগুলি ব্যবহার করতে চাই।

সুতরাং আমার নিম্নলিখিত মডিউলটি কল্পনা করুন

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);

আমার যা ইচ্ছা তা করা সম্ভব কিনা তা কি কেউ জানেন বা আমি ভুল গাছটিকে পুরোপুরি ছাঁটাই করছি ??

--- ফলোআপ করুন: মনে হয় আমি ইন্টারফেসে @ ইমপ্লিমেন্টেড বাই ট্যাগটি ব্যবহার করি এবং তারপরে পরীক্ষার ক্ষেত্রে একটি বাঁধাই সরবরাহ করি তবে আমি যা চাই তা অর্জন করতে পারি, যা 1-1 এর মধ্যে 1-1 ম্যাপিংয়ের সময় দুর্দান্তভাবে কাজ করে ইন্টারফেস এবং বাস্তবায়ন।

এছাড়াও, কোনও সহকর্মীর সাথে এটি আলোচনা করার পরে মনে হবে আমরা একটি সম্পূর্ণ মডিউলকে ওভাররাইড করে আমাদের মডিউলগুলি সঠিকভাবে সংজ্ঞায়িত করার বিষয়টি নিশ্চিত করব road এটি দেখে মনে হচ্ছে এটি সমস্যা তৈরি করতে পারে যদিও মডিউলটিতে একটি বাঁধাই ভুল জায়গায় স্থানান্তরিত করা দরকার এবং সম্ভবত এটি পরীক্ষা করা অনেকটা ব্রেক করা সম্ভবত বাইন্ডিংগুলি ওভাররাইডের জন্য আর উপলব্ধ না হয়ে থাকতে পারে।


7
"ভুল গাছের ঝাঁকুনি" শব্দটির মতো: ডি
বরিস পাভলোভিć

উত্তর:


149

আপনি যে উত্তরটি সন্ধান করছেন এটি এটি নাও হতে পারে তবে আপনি যদি ইউনিট পরীক্ষা লিখছেন তবে আপনার সম্ভবত কোনও ইনজেক্টর ব্যবহার করা উচিত নয় বরং হাত দিয়ে মক বা নকল জিনিস ইনজেকশন করা উচিত।

অন্যদিকে, আপনি যদি সত্যিই একটি একক বাঁধাই প্রতিস্থাপন করতে চান তবে আপনি এটি ব্যবহার করতে পারেন 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()));

বিস্তারিত এখানে দেখুন ।

তবে জাভাডোকের Modules.overrides(..)পরামর্শ অনুসারে আপনার মডিউলগুলি এমনভাবে ডিজাইন করা উচিত যাতে আপনাকে বাইন্ডিংগুলিকে ওভাররাইড করার প্রয়োজন হয় না। আপনি যে উদাহরণ দিয়েছেন, আপনি এটি InterfaceCপৃথক মডিউলে বাঁধাই করে তা অর্জন করতে পারেন ।


9
ধন্যবাদ অ্যালবার্ট, এটি আমাকে যা করতে চায় তার পথে একরকম পথে নামিয়ে দেয়। এটি এখনও প্রযোজনায় মুক্তি পাচ্ছে! এবং এটি ইউনিট পরীক্ষার জন্য নয়, ইন্টিগ্রেশন পরীক্ষার জন্য, আমি কেন অন্য সব কিছু সঠিকভাবে নির্মিত হচ্ছে তা নিশ্চিত করতে চাই
tddmonkey

1
আমি কোডটিতে একটি দৃ concrete় উদাহরণ যুক্ত করেছি। এটি কি আপনাকে আরও এগিয়ে নিয়ে যায়?
albertb

1
যতক্ষণ না আমি ভুল হয়ে থাকি, তা করার সময় ovverideযথাযথ হারায় Stage(যেমন ডেভেলপমেন্ট পদ্ধতিগতভাবে ব্যবহৃত হয়)।
pdeschen

4
আকার বিষয়ে. যখন আপনার নির্ভরতা গ্রাফটি বড় হয়, তখন হাত দিয়ে তারের আপ করা বেশ ব্যথা হতে পারে। তারের পরিবর্তনের সময় আপনাকে নিজের সমস্ত ম্যানুয়াল ওয়্যারিংয়ের জায়গাগুলি ম্যানুয়ালি আপডেট করতে হবে। ওভাররাইডিং আপনাকে স্বয়ংক্রিয়ভাবে এটি পরিচালনা করতে দেয়।
ইয়ুসিবা

3
@pdeschen এটি গুইস 3-এ একটি বাগ যা আমি গুইস 4 এর জন্য স্থির করেছি
তাভিয়ান বার্নস

9

উত্তরাধিকার ব্যবহার করবেন না কেন? 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());

3
@Overrideকাজ বলে মনে হচ্ছে না। বিশেষত যদি এটি কোনও পদ্ধতিতে করা হয় যে @Providesকিছু।
সাসাঙ্কা পাঙ্গুলুরী 21

4

আপনি যদি নিজের প্রোডাকশন মডিউলটি পরিবর্তন করতে না চান এবং যদি আপনার কোনও ডিফল্ট মেভেন-জাতীয় প্রকল্প কাঠামো থাকে

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

আপনি ConcreteCনিজের পরীক্ষার ডিরেক্টরিতে আপনার মূল বর্গ হিসাবে একই প্যাকেজটি ব্যবহার করে কেবল নতুন পরীক্ষা তৈরি করতে পারেন । Guice তারপর বাঁধবে InterfaceCকরতে ConcreteCআপনার পরীক্ষার ডিরেক্টরি থেকে যেহেতু সব অন্যান্য ইন্টারফেসগুলি আপনার উৎপাদন শ্রেণীর বাধ্য করা হবে না।


2

আপনি 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();
    }
}

1

ভিন্ন সেটআপে, আমাদের পৃথক মডিউলগুলিতে একাধিক ক্রিয়াকলাপ সংজ্ঞায়িত করা হয়। যে ক্রিয়াকলাপটি ইনজেক্ট করা হচ্ছে তা অ্যান্ড্রয়েড লাইব্রেরি মডিউলটিতে রয়েছে যার অ্যান্ড্রয়েড ম্যানিফেস্ট.এক্সএমএল ফাইলে তার নিজস্ব রোবোগুইস মডিউল সংজ্ঞা রয়েছে।

সেটআপটি দেখতে এমন দেখাচ্ছে। লাইব্রেরী মডিউলটিতে এই সংজ্ঞা রয়েছে:

Andro আইডি:

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

তারপরে আমাদের এক ধরণের ইনজেকশন দেওয়া হচ্ছে:

interface Foo { }

ফু এর কিছু ডিফল্ট বাস্তবায়ন:

class FooThing implements Foo { }

মেইনমডিউল ফু এর জন্য ফুচিং বাস্তবায়ন কনফিগার করেছে:

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

এবং পরিশেষে, একটি ক্রিয়াকলাপ যা ফু গ্রহণ করে:

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

গ্রাসকারী অ্যান্ড্রয়েড অ্যাপ্লিকেশন মডিউলটিতে, আমরা ব্যবহার করতে চাই SomeActivityতবে পরীক্ষার উদ্দেশ্যে, আমাদের নিজস্ব ইনজেকশন Foo

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

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

মডিউলটি ক্লায়েন্ট অ্যাপ্লিকেশনে হ্যান্ডলিংয়ের বহিঃপ্রকাশের জন্য কেউ তর্ক করতে পারে, তবে, আমাদের বেশিরভাগ অংশগুলি ইনজেকশনের উপাদানগুলি লুকিয়ে রাখা দরকার কারণ লাইব্রেরী মডিউলটি একটি এসডিকে, এবং এক্সপোজিং টুকরোটির বৃহত প্রভাব রয়েছে।

(মনে রাখবেন, এটি পরীক্ষার জন্য, সুতরাং আমরা সামারঅ্যাক্টিভিটির ইন্টার্নালগুলি জানি এবং জানি এটি কোনও (প্যাকেজ দৃশ্যমান) ফু ব্যবহার করে)।

আমি যেভাবে কাজ করেছিলাম তা বোঝা যায়; পরীক্ষার জন্য প্রস্তাবিত ওভাররাইড ব্যবহার করুন :

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 এবং এটি নির্বিঘ্নে কাজ করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.