I've set up a very simple project to test the integration of Robolectric + Data Binding + Retrolambda. When I run the test suit, I get the following message:
Error:(30, 30) Gradle: error: cannot access AndroidHttpClient
class file for android.net.http.AndroidHttpClient not found
This is pretty odd since I don't use AndroidHttpClient anywhere.
The error occurs here, on the "activity" line:
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class); // Error on this line
textView = (TextView) shadowOf(activity).findViewById(R.id.textView);
button = (Button) activity.findViewById(R.id.button);
editText = (EditText) activity.findViewById(R.id.editText);
}
The program never uses AndroidHttpClient. In fact, this is the entire program:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(new User());
binding.button.setOnClickListener((v) -> {
binding.textView.setText(String.format("Hello, %s!", binding.editText.getText()));
binding.editText.setText("");
});
}
Ideas as to what's wrong?
AndroidHttpClient was removed from the SDK in v23 of the build tools.
As Robolectric is running against earlier versions, it expects it to be there, which is why you're seeing this error.
For now, you can add it back in:
android {
useLibrary 'org.apache.http.legacy'
}
As detailed here.
There is a GitHub ticket open for Robolectric to fix this. You can follow the thread/ticket here.
Update:
As some people have correctly pointed out, a better way of doing this would be to create a class android.net.http.AndroidHttpClient in your test resources. This would be a preferred method because you're only modifying the test sources, not the production code, in order to accommodate the tests.
I've just added fake class android.net.http.AndroidHttpClient in my test sources. And it solved the issue for now. Waiting for Robolectric to be updated
Apparent problem and solution:
AndroidHttpClient was removed from the SDK in API Level 23, while Robolectric was set to run tests with SDK 21:
AndroidHttpClient was removed from the SDK in API Level 23
I was able to solve this problem by creating a new class called AndroidHttpClient within a new package android.net.http. After that I had to annotate my Unit Test class with #Config(constants = BuildConfig.class, sdks = 21) which will run the tests against an emulated version of API 21 which is the last version of Android Robolectric supports currently.
There is currently an issue opened here, so once they release version 3.1 everything should be fine and you won't have to use this workaround.
If target SDK is 28 or greater then according to this, we have to put following line in AndroidManifest.xml
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
Related
I have imported
implementation 'com.google.android.things:androidthings:1.0'
And when I execute code, it throws a runtime error because inside of the PeripheralManager class the methods are all stubs:
public List<String> getUartDeviceList() {
throw new RuntimeException("Stub!");
}
This was working several months ago, I've tried changing implementation to compile
There are several conditions you should verify in your project:
Your device must be either the i.MX7D or Raspberry Pi 3B with the Android Things OS on it, as noted in the hardware guide.
Your app/build.gradle must use compileOnly 'com.google.android.things:androidthings:1.0'
Your app/src/main/AndroidManifest.xml must include the following as a child of the application element:
<uses-library android:name="com.google.android.things"/>
You may also want to check properties like the targetSdkVersion being 27. If you continue to run into trouble, check out Android Things sample projects.
Which device are you running it into? This API is only available on Android Things boards, not on phones.
Android Studio 3.0 Beta2
classpath 'com.android.tools.build:gradle:3.0.0-beta3'
testCompile 'org.robolectric:robolectric:3.4.2'
Test class that I am using that fails to run:
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
#RunWith(RobolectricTestRunner.class)
public class RecipeAdapterTest {
private MainActivity activity;
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class);
/* Also tried this same Error
activity = Robolectric.buildActivity(MainActivity)
.create()
.resume()
.get();
*/
}
#Test
public void testActivityShouldNotBeNull() {
assertThat(activity, is(notNullValue()));
}
}
This is the stack trace of the error:
android.content.res.Resources$NotFoundException: String resource ID #0x7f0c0020
at android.content.res.Resources.getText(Resources.java:274)
at android.content.res.Resources.getString(Resources.java:360)
at android.content.Context.getString(Context.java:376)
at org.robolectric.shadows.ShadowActivity.getActivityTitle(ShadowActivity.java:100)
at org.robolectric.shadows.ShadowActivity.callAttach(ShadowActivity.java:110)
at org.robolectric.android.controller.ActivityController.attach(ActivityController.java:56)
at org.robolectric.android.controller.ActivityController.of(ActivityController.java:25)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:98)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:94)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:102)
at me.androidbox.busbybaking.adapters.RecipeAdapterTest.setup(RecipeAdapterTest.java:63)
In the Edit Configurations I have set the Working Directory to $MODULE_DIR$
Many thanks for any suggestion.
As mentioned by an engineer from Google team (most possibly Xavier Ducrohet), Robolectric has issues with AAPT2:
Robolectric is not compatible with aapt2.
Two options here.
First option - follow Robolectric guidelines for Android Studio 3.0+
Add the following to your build.gradle:
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
Annotate your test with the Robolectric test runner:
#RunWith(RobolectricTestRunner.class)
public class SandwichTest {
}
Second option: disable AAPT2 adding following line into gradle.properties file:
android.enableAapt2=false
The Robolectric documentation states that the following configuration should be used with Android Studio 3.x:
android {
testOptions {
unitTests.includeAndroidResources true
}
}
(for anyone that might be looking for a solution to a similar problem)
Be sure to use
RuntimeEnvironment.application
and not:
RuntimeEnvironment.systemContext
when you're trying to resolve resources "manually".
That's one case in which Resources$NotFoundException might show up with Robolectric.
Not a direct answer to the question, but if you are testing something that needs a context to query resources against I have found the following to work quite well:
ApplicationProvider.getApplicationContext()
(or RuntimeEnvironment.application -- but this is deprecated in favor of the above)
If your build fails due to an AAPT2 resource processing issue or you want to use Roboelectric, you can disable AAPT2 by setting android.enableAapt2=false in your gradle.properties file and restarting the Gradle daemon by running ./gradlew --stop from the command line.
Official guideline Android Studio 3.0 Release
I was using espresso, and for that you needed to use app resources, not test resources.
So instead of
InstrumentationRegistry.getInstrumentation().context.resources.getString("key")
I used
activityRule.activity.getString("key")
In my case the following solved my issue:
"Problem is related to android studio. Go to 'Run' -> 'Edit configurations...' and change 'Working directory' value to
$MODULE_DIR$
Run your tests.
More info here under 'Building with Android Studio'."
reference: https://github.com/robolectric/robolectric/issues/2653
You can also try #Config(manifest = "<projectFolder>/src/main/AndroidManifest.xml") in the case that you can not simply include the resources as some projects tests will fail with that included.
This test originally ran fine. Checked out a new branch several days later (with commits from many other developers) and it no longer works.
Test class in the mylibrary library module:
import com.company.mylibrary.BuildConfig;
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, manifest = "src/main/AndroidManifest.xml", sdk = 21)
public class MyTest {
I have also tried:
#Config(constants = BuildConfig.class, sdk = 21)
#Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 21)
In the library module's build.gradle
dependencies {
.
.
testCompile 'org.robolectric:robolectric:3.0'
Error message when running inside AS is:
java.lang.RuntimeException: build/intermediates/manifests/full/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
Error message when running from command line is:
com.company.mylibrary.framework1.feature1.MyTest > testMethod STANDARD_ERROR
java.lang.RuntimeException: build/intermediates/manifests/full/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
A) Don't know why it is looking there for the manifest
B) That file/directory does not exist
C) src/main/AndroidManifest.xml does exist
Things I have tried:
- deleted the build directory in that library module
- restarted Android Studio
- Build/Clean
- Build/Rebuild Project
- run the test (both inside AS and from command line)
- and tried different versions of the #Config notation
Seems to be in a wonky state that I cannot clear.
I am working on a MacBook Pro. Android Studio 2.0 beta5
You need to set the working directory within the test's run configuration to the module directory.
Well, I've tackled the issue you're facing right now several times and found solution suitable for myself.
Generally, if your test logic does not require access to the application's resources, it's worth using usual RobolectricTestRunner as the time of the test execution is relatively shorter comparing it to the test execution time under RobolectricGradleTestRunner.
If, for some reason, you need access to the specific AndroidManifest.xml file, IMO it's better to come up with test file rather than to operate on the project's one.
By saying 'test file' I mean the following:
Let's start by defining what are the methods that can help us to obtain path to the resources files. The goal is to be able execute tests under Android Studio and, what's more relevant, via CLI (gradle :project:testBuildTypeUnitTest)
Java's System class: System.getProperty('user.dir') returns User's current working directory. Obtaining current directory we are in may help us to obtain paths to the resources we need to run our test having them provided.
Overriding RobolectricGradleTestRunner. To create our customized test runner we need the AndroidManifest.xml, the res directory and the assets directory paths:
public class CompassApplicationRobolectricTestRunner extends RobolectricGradleTestRunner {
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.LOLLIPOP;
private static final int MIN_SDK_VERSION = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
public CompassApplicationRobolectricTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected AndroidManifest getAppManifest(Config config) {
final String manifestPath = PathResolver.resolveAndroidManifestPath();
final String resourcesPath = PathResolver.resolveResPath();
final String assetsPath = PathResolver.resolveAssetsPath();
AndroidManifest manifest = new AndroidManifest(
Fs.fileFromPath(manifestPath),
Fs.fileFromPath(resourcesPath),
Fs.fileFromPath(assetsPath)) {
#Override
public int getTargetSdkVersion() {
return TARGET_SDK_VERSION;
}
#Override
public int getMinSdkVersion() {
return MIN_SDK_VERSION;
}
};
return manifest;
}
}
Below, is the link to the example that worked for me. It was developed, however, some time ago and from the time perspective I see it can be done more elegant way so if you decide to apply this solution to your project, organize your path constants to be static and immutable:
https://github.com/dawidgdanski/android-compass-api/blob/master/app-tests/src/test/java/pl/dawidgdanski/compass/PathResolver.java
It's worth remembering that File.separator returns system's default directories separator. It's extremely useful when it comes to provide system-independent paths separated with default separation symbol.
Eventually, if the solution described above is not the one you want to follow, read decent article about setting up testing environment available here:
http://artemzin.com/blog/how-to-mock-dependencies-in-unit-integration-and-functional-tests-dagger-robolectric-instrumentation/
Hope that solves your problem.
In my case, I was running a single test manually (Right click and run) from inside Android Studio and Roboelectric wanted a RELEASE version. The question above was about debug but my test runs for some reason wanted a release version of the manifiest.
java.lang.RuntimeException: build/intermediates/manifests/release/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
I had never done a production build in this project so that build directory had never been created.
After wrestling for a bit with no success (setting the path in configuration, trying to get the path in my CustomRoboelectric file), I just generated a production build so that I had the release path created with a manifest and everything worked.
So my solution was to just run the build to create what Roboelectric wanted.
I'm trying to come to terms with the new unit test feature of Android Studio.
I've followed the instructions on http://tools.android.com/tech-docs/unit-testing-support. The description there explicitly mentions the 'Method ... not mocked' error and suggests to put the following into the build.gradle:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
This works in so far as the tests run when started from the command line with
gradlew test --continue
but not when I run the test class from Android Studio with rightclick -> run. This way, I get the same error again:
java.lang.RuntimeException: Method setUp in android.test.AndroidTestCase not mocked. See https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support for details.
at android.test.AndroidTestCase.setUp(AndroidTestCase.java)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Any ideas on how to solve this?
EDIT: The content of the test class doesn't really matter because the setUp of the test fails, I tried with the most simple class:
public class ContactFormToolTest extends AndroidTestCase {
public void testSOmething(){
assertEquals(false, true);
}
}
Also tried overriding setUp, makes no difference.
From: https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support#TOC-Method-...-not-mocked.-
The android.jar file that is used to run unit tests does not contain
any actual code - that is provided by the Android system image on real
devices. Instead, all methods throw exceptions (by default). This is
to make sure your unit tests only test your code and do not depend on
any particular behaviour of the Android platform (that you have not
explicitly mocked e.g. using Mockito). If that proves problematic, you
can add the snippet below to your build.gradle to change this
behavior:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
The new Unit Tests feature in Android Studio fakes the entire Android SDK so that you can run fast, Java-only tests, without needing to install your application on an Android device (this is similar to Robolectric). The general idea is that you mock all the responses from the Android SDK calls.
AndroidTestCase is used to run a test with the real Android SDK.
So, your issue is that you are trying to run an AndroidTestCase that depends on the Android SDK, but your test runner is launching the Unit Tests environment, which uses a fake Android SDK instead of a real one.
You need to choose one approach. If you want a pure unit test, then you probably should use a JUnit 4 test class instead of an AndroidTestCase. More instructions here:
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html#build
As of SDK version 24, AndroidTestCase is deprecated
This class was deprecated in API level 24.
Use InstrumentationRegistry instead. New tests should be written using
the Android Testing Support Library.
You are supposed to use the Espresso framework for UI testing. There is a tutorial.
Do anyone know how to integrate robolectric into android studio?
How to write sample test?
How to launch it?
I am working with android studio not to long, and I am too bad with gradle.
Searching the net didn't give me a result - I even could not launch official demo - https://github.com/robolectric/robolectric-samples . My android studio do not saw the test class.
Please give me simpliest step by step gide, thanks
Since robolectric runs in a JVM (i.e. not on a device or emulator), it is just a library and adding the test runner is all that's needed.
Make sure that the android SDK is later in the classpath than robolectric or junit - otherwise you'll get the stubbed methods from the android SDK.
#RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
#Test
public void shouldHaveApplicationName() throws Exception {
String appName = new MyActivity().getResources().getString(R.string.app_name);
assertThat(appName, equalTo("MyActivity"));
}
}
See http://robolectric.org/quick-start/