I am very much new to Robolectric. I am facing these issues after migrating from Robolectric v3.0 to v3.4.1.
Robolectric is not loading my AppController class which extends Application
I am getting class cast exception on casting to RuntimeEnvironment.application to my AppController, which shouldn't be the case as my AppController extends Application and was working fine before migrating to latest version.
Please find the code below for my test
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, manifest = "app/src/main/AndroidManifest.xml", sdk = 21)
public class FragmentTest {
private ExampleFragment fragment = SupportFragmentController.of(new ExampleFragment()).create().get();
private Context mContext;
#Before
public void setUp() throws Exception {
// RuntimeEnvironment.application.onCreate();
mContext =RuntimeEnvironment.application ;
}
#Test
public void testFragmentInstantiation() {
ExampleFragment.mAppController = (AppController)mContext;
}
To reproduce - run any test.
Robolectric version is 3.4.1.
The main advice is to do not put manifest file location in the #Config section unless you know what you're doing. So please change your test annotations to:
#Config(constants = BuildConfig.class, sdk = 21)
Also, I don't know if it is by purpose but you could use much newer android sdk in your test with the newest version of Robolectric
Related
I just want to test that getting a String resource equals what I think it should equal. My issue seems to be that I have Realm in my project. I know that Robolectric doesn't support Realm (it states it in the documentation), but I'm not invoking Realm at all, so I feel like there might be a way to do this.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21, manifest = "app/src/main/AndroidManifest.xml")
public class ResourceTester {
#Test
public void testingString() {
String resourceString = RuntimeEnvironment.application.getString(R.string.app_name);
assertEquals(resourceString, "Yeah");
}
}
It does look like it IS trying to invoke Realm
java.lang.UnsatisfiedLinkError: Can't load library:
/var/folders/3x/ddxtg5fs1hxgqrp6h63vsc140000gp/T/android-tmp-
robolectric3612430387389787158/app_lib/librealm-jni.dylib.3.5.0
EDIT: I tried some more things, and it seems like setting the manifestin the #Config annotation is the issue, but then I get a android.content.res.Resources$NotFoundException: unknown resource 2131362072
Any other thoughts? Can I make another Application class where Realm isn't called? How would the /test directory know that?
EDIT FOR DAVID:
I tried this:
#RunWith(RobolectricGradleTestRunner.class)
#Config(application = TestingApplication.class, constants = BuildConfig.class, sdk = 21)
public class ResourceTester {
#Test
public void newTestingTests() throws Exception {
String appName = RuntimeEnvironment.application.getString(R.string.app_name);
}
}
but I get a:
android.content.res.Resources$NotFoundException: unknown resource 2131362072
If I change it to
#RunWith(RobolectricTestRunner.class)
//#RunWith(RobolectricGradleTestRunner.class)
#Config(application = TestingApplication.class, constants = BuildConfig.class, sdk = 21)
public class ResourceTester {
#Test
public void newTestingTests() throws Exception {
String appName = RuntimeEnvironment.application.getString(R.string.app_name);
}
}
I get
WARNING: No manifest file found at ./AndroidManifest.xml.Falling back to the Android OS resources only.
To remove this warning, annotate your test class with #Config(manifest=Config.NONE).
android.content.res.Resources$NotFoundException: unknown resource 2131362072
If you have a heavyweight Application class (e.g., with dependencies on Realm, Crashlytics etc.) and your unit tests do not refer to these you can use android.app.Application as your Application class in the config:
#RunWith(RobolectricTestRunner.class)
#Config(application = android.app.Application.class, manifest="src/main/AndroidManifest.xml", sdk = 23)
public class ResourceTester {
Also make sure you have Working Directory set to $MODULE_DIR$ if you are using Mac or Linux as per the getting started instructions
I tried running robolectric library with versions 3.3.2 and 3.4-rc3. My code internally tries to fetch a singleton instance of the application. But when my test runs, the application instance retrieved is always null. It works fine with robolectric 3.1.2. I wanted to upgrade as I wanted to use powermocks in the test. There were similar questions in stackoverflow. But it did not help me. Please advise. Following is my test code. I tried running with PowerMockRunnerDelegator as shown here. Also, tried with the normal RobolectricTestRunner as the Runner. Both the approaches did not work.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21, application =
TestApplication.class)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*",
"android.*"})
#PrepareForTest({MockActor.class})
public class MyTest {
#Mock
private MockActor mockActorInstance;
#Rule
public PowerMockRule rule = new PowerMockRule();
#Before
public void setup() throws Exception {
initMocks(this);
PowerMockito.mockStatic(MockActor.class);
whenNew(MockActor.class).withAnyArguments()
.thenReturn(mockActorInstance);
}
#Test
public void shouldTriggerCall() {
MyFragment myFragment = new MyFragment();
startFragment(myFragment);
myFragment.doAction();
verify(mockActorInstance).invoke();
}
}
You can implement a custom ShadowApplication and stub your static getApplication method there. Hopefully this https://medium.com/#chuangx/get-around-with-app-getapplication-in-robolectric-4b88d559fca5 helps
Using: Cucumber-JVM with Android Instrumentation + Espresso).
Reference Github link: https://github.com/mfellner/cucumber-android for this. The simple sample works fine.
Problem with cucumber-jvm + android instrumentation:
But in the sample in link, it uses ActivityInstrumentationTestCase2 which is deprecated. I would like to use #Rule - ActivityTestRule class as said by Google.
Here my question is:
For using cucumber-jvm, I am using the CucumberInstrumentationCore instead of
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner".
So Android junit annotations like #Rule for ActivityTestRule is not parsed by CucumberInstrumentation. So Is it possible to overcome this problem?
Then is my decision to use cucumber-jvm + android instrumentation has to be reverted back. My question is not only for the deprecated class but globally is it good idea to go for cucumber-jvm + android instrumentation, as it can't use instrumentation features because of annotation parsing.
Your runner should inherit from Android JUnitRunner:
public class Instrumentation extends AndroidJUnitRunner {
private final CucumberInstrumentationCore instrumentationCore = new CucumberInstrumentationCore(this);
#Override
public void onCreate(final Bundle bundle) {
instrumentationCore.create(bundle);
super.onCreate(bundle);
}
#Override
public void onStart() {
waitForIdleSync();
instrumentationCore.start();
}
Pay attention to the super class been initialized at the end of onCreate.
Then, edit your defaultConfig in your build.grade file:
defaultConfig {
applicationId "your.package.name"
testApplicationId "your.steps.package"
testInstrumentationRunner "your.package.Instrumentation"
}
And finally, the steps definition class, which inherited from ActivityInstrumentationTestCase2 should look like:
public class BaseStepDefinitions {
public static final String TAG = BaseStepDefinitions.class.getSimpleName();
#Rule
public ActivityTestRule<StartupActivity> mActivityRule = new ActivityTestRule<>(StartupActivity.class);
#Before
public void setUp() throws Exception {
mActivityRule.launchActivity(null);
mActivityRule.getActivity();
}
/**
* All the clean up of application's data and state after each scenario must happen here
*/
#After
public void tearDown() throws Exception {
}
#When("^I login with \"([^\"]*)\" and \"([^\"]*)\"$")
public void i_login_with_and(String user, String password) throws Throwable {
// Login...
}
The setUp function runs before each scenario, and launching the activity.
Globally, if it serves your needs I don't see any problem using it like so, both Cucumber annotations and the JUnit annotations can be parsed in this way.
I've created a sample project: github.com/Clutcha/EspressoCucumber
I have written a class to manage logging within an android application project.
The LogManager is basically a wrapper for android.util.log
It handles logging to a file, if the application crashes, and standard debug logging.
I would like to unit test the class using JUnit.
I have tried the following but it does not seem to produce the results I would expect after reading the examples:
LogManager.class (This is a simplified version of the class I have used, for demonstration purposes)
public class LogManager implements ILogManager
{
public void log(String tag, String message)
{
Log.e(tag, message);
}
}
And here is my test class
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21)
#PrepareForTest({Log.class, LogManager.class})
public class LogManagerUnitTest
{
#Test
public void testLogConsoleInfo()
{
PowerMockito.mockStatic(Log.class);
LogManager.getInstance().log(LogLevel.INFO, "test", "test");
PowerMockito.verifyStatic(Mockito.times(1));
Log.e(anyString(), anyString());
}
}
My problem is that this passes no matter what I put.
E.g: if I instead replace the last call with Log.wtf(...) it still passes. I would have assumed that it should fail since Log.wtf was not called in the static class Log?
So my question is, why isn't this approach working as expected and what would be the correct way to do it?
I started a fresh project and was able to get it to fail tests and succeed appropriately using the following, so I'm assuming the runwith was the culprit:
#RunWith(PowerMockRunner.class)
#PrepareForTest(android.util.Log.class)
public class LoggerUnitTest {
#Test
public void testLog() throws Exception
{
PowerMockito.mockStatic(Log.class); // when(Log.e(anyString(), anyString())).thenReturn(1);
Logger.log("test", "test");
PowerMockito.verifyStatic(times(1));
Log.e(anyString(), anyString());
} }
For the RobolectricGradleTestRunner, the following incantation would have exposed your logging:
ShadowLog.stream = System.out
Robolectric does not print the Android system logging by default.
It's also worth noting that the RobolectricGradleTestRunner has been deprecated in favor of the fully operational RobolectricTestRunner (The above assignment is still effective)
I am developing an Android app with Android Studio, using Gradle as build tool. Integration with Android Studio and Robolectric is done with android-unit-test gradle plugin.
I am also using ORMLite (latest version).
Is there a way I can test ORMLite DAO's with Robolectric 2.3-SNAPSHOT?
In such version some shadows were dropped, include SQLite ones (see Robolectric dropping SQLite shadows commit). I looked at some unit tests in Robolectric repo, like this, but I need some information on how to setup the interaction with ORMLite.
Here is a working example I was able to compile and run.
#Config(emulateSdk = 18) // because Robolectric does not yet support API Level 19
#RunWith(RobolectricTestRunner.class)
public class DatabaseHelperManagerTest extends BaseTest {
private Context context;
public void initContext() {
context = Robolectric.application.getApplicationContext();
assertNotNull(context);
}
#BeforeClass
public static void setup(){
// To redirect Robolectric to stdout
System.setProperty("robolectric.logging", "stdout");
}
#Test
public void getDatabaseHelperTest(){
initContext();
DatabaseHelperManager databaseHelperManager = new DatabaseHelperManager();
DatabaseHelper databaseHelper = databaseHelperManager.getHelper(context);
assertNotNull(databaseHelper);
Log.d(DatabaseHelperManagerTest.class.getName(), "Database Path:" + context.getDatabasePath(DatabaseHelper.DATABASE_NAME));
}
}
For reference (in the DatabaseHelperManager class):
public DatabaseHelper getHelper(Context context) {
return OpenHelperManager.getHelper(context, DatabaseHelper.class);
}