Как внедрить зависимости в класс Robolectric Test с помощью RoboGuice

Я хочу начать использовать Robolectric и RoboGuice в своих Android-приложениях. Пока я добиваюсь удовлетворительных результатов с помощью Robolectric, я застрял на RoboGuice. Я создал небольшое Android-приложение для экспериментов. Это только одно действие, внедряющее кнопку и устанавливающее ее OnClickListener. В соответствующем тестовом классе я хочу внедрить это действие, чтобы иметь возможность протестировать кнопку. Я пробовал много вещей, которые нашел в Интернете, но ничего из этого не сработало, поэтому я попробую здесь. Вот код:

Основная активность.java:

package com.example.TrialApp;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import roboguice.activity.RoboActivity;
import roboguice.inject.InjectView;

public class MainActivity extends RoboActivity implements View.OnClickListener {

    @InjectView(R.id.main_LoginButton) private Button loginButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        loginButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        SharedPreferences.Editor editor;
        if (view.getId() == R.id.main_Login_Button)
            Log.i("Login-Button pressed... ", "");
    }
}

CustomRobolectricTestRunner.java:

package com.example.TrialApp;

import com.xtremelabs.robolectric.RobolectricTestRunner;
import org.junit.runners.model.InitializationError;

import java.io.File;
public class CustomRobolectricTestRunner extends RobolectricTestRunner {
    public CustomRobolectricTestRunner(Class testClass) throws InitializationError {
        // defaults to "AndroidManifest.xml", "res" in the current directory
        super(testClass, new File("TrialApp"));
    }
}

MainActivity_Test.java:

package com.example.TrialApp;

import com.google.inject.Inject;
import com.xtremelabs.robolectric.Robolectric;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertNotNull;

@RunWith(CustomRobolectricTestRunner.class)
public class MainActivity_Test {

    @Inject MainActivity mainActivity;
    @Inject ClassWithoutAName classWithoutAName;

    @Before
    public void setUp() {

    }

    @Test
    public void mainActivityShouldNotBeNull() {
        assertNotNull(mainActivity);
    }

    @Test
    public void classWithoutANameShouldNotBeNull() {
        assertNotNull(classWithoutAName);
    }
}

classWithoutAName - это просто класс без активности без содержимого. Я добавил только для внедрения класса без активности.

При запуске Test-Class оба теста завершаются неудачно, выдавая следующие ошибки:

java.lang.AssertionError
at com.example.TrialApp.MainActivity_Test.mainActivityShouldNotBeNull(MainActivity_Test.java:33) <8 internal calls>
at com.xtremelabs.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:288) <16 internal calls>

а также

java.lang.AssertionError
at com.example.TrialApp.MainActivity_Test.classWithoutANameShouldNotBeNull(MainActivity_Test.java:38) <8 internal calls>
at com.xtremelabs.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:288) <16 internal calls>

Очевидно, чего-то не хватает. Внедрение в MainActivity работает нормально, и приложение работает.
Почему тот же шаблон внедрения зависимостей в Robolectric-Testclass не работает? Где недостающая ссылка?
Спасибо.


person Frank    schedule 16.04.2013    source источник


Ответы (1)


Прочитав еще несколько статей и тем, я нашел частичное решение. Я до сих пор не нашел способ внедрить UI-элементы в тестовый класс, но я узнал, как внедрить не-UI-элементы в тестовый класс. Хитрость заключается в том, чтобы реализовать «RobolectricTestModule», расширяющий AbstractModule. Привязки, сделанные в модулях, объявленных в roboguice.xml, отсутствуют в тестовой среде, поэтому нам нужно объявить привязки для тестовой среды в этом дополнительном модуле. В настроенном Testrunner мы заменяем DefaultRoboModule новым RobolectricTestModule.
ClassWithoutAName.java:

package com.example.TrialApp;

public class ClassWithoutAName {

    private String string;

    public ClassWithoutAName(String string) {
        this.string = string;
    }

    public String getString() {
        return string;
    }
}

ClassWithoutANameProvider.java

package com.example.TrialApp.GuiceModules;

import com.example.TrialApp.ClassWithoutAName;
import com.google.inject.Provider;

public class ClassWithoutANameProvider implements Provider<ClassWithoutAName> {
    @Override
    public ClassWithoutAName get() {
        return new ClassWithoutAName("testString");
    }
}

ClassWithOutANameModule.java

package com.example.TrialApp.GuiceModules;

import com.example.TrialApp.ClassWithoutAName;
import com.google.inject.AbstractModule;

public class ClassWithOutANameModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(ClassWithoutAName.class).toProvider(ClassWithoutANameProvider.class);
    }
}

RobolectricTestModule.java

package com.example.TrialApp.GuiceModules;

import com.example.TrialApp.WeirdThings;
import com.google.inject.AbstractModule;

public class RobolectricTestModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(ClassWithoutAName.class).toProvider(ClassWithoutANameProvider.class);
    }
}

CustomRobolectricTestRunner.java

package com.example.TrialApp;

import android.app.Application;
import com.example.TrialApp.GuiceModules.RobolectricTestModule;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner;
import org.junit.runners.model.InitializationError;
import roboguice.RoboGuice;

import java.io.File;

public class CustomRobolectricTestRunner extends RobolectricTestRunner {

    public CustomRobolectricTestRunner(Class testClass) throws InitializationError {
       // defaults to "AndroidManifest.xml", "res" in the current directory
        super(testClass, new File("TrialApp"));
    }

    @Override
    public void prepareTest(Object test) {
        Application application = (Application) Robolectric.application;

        RoboGuice.setBaseApplicationInjector(application, RoboGuice.DEFAULT_STAGE,
                RoboGuice.newDefaultRoboModule(application), new RobolectricTestModule());

        RoboGuice.getInjector(application).injectMembers(test);
    }
}

Вот и все для не-UI-элементов.

person Frank    schedule 18.04.2013