Iam attempting to convert a resource image to a bitmap to test it in an Instrumentation test in android. originally i had this as a regular test extending testcase. my issue is with this
protected void setUp()
{
testbmap=BitmapFactory.decodeResource(getInstrumentation().
getContext().getResources(), R.drawable.ic_launcher);
}
then i test that the bitmap is not null but the test fails.
public void testnotnull()
{
assertNotNull(testbmap);
}
so iam doing something wrong here i think it could b something to do with the first param in the decoderecource(), maybe iam not pointing to the correct resources? I also tried getApplicationContext.getResources() method but iam not too sure on this one.
can anyone help me?
I solved this problem changing #getContext() which will return Context of instrumentation's package to #getTargetContext() which will return context of target application.
Return a Context for the target application being instrumented. Note
that this is often different than the Context of the instrumentation
code, since the instrumentation code often lives is a different
package than that of the application it is running against. See
getContext to retrieve a Context for the instrumentation code.
Kotlin method:
#Test
fun bitmapIsNotNull() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val bitmap = BitmapFactory.decodeResource(context.resources, R.raw.any_image)
Assert.assertNotNull(bitmap)
}
Related
Hello I have the following project structure
--App
|--SDK1
|--SDK2
In app I have some test for check SDK1 and SDK2.
In SDK I have a singleton pattern only to set the context by the application class that is in App.
And the context is set in the SDK1.singleton in the App.Application.onCreate
The problem is that when I try to execute the following code I always get null:
#RunWith(RobolectricTestRunner.class)
public class CallTest {
#Before
public void setUp() throws Exception {}
#Test
public void connectToSocketTest() {
if (BuildConfig.FLAVOR.equals("dev")) {
Context context = SDK1.getInstance().getContext();
assertNotNull(context);
...
Any idea why this happens, and how can solve it?
That's not the recommended way to get app context in Android using robolectric. You can get your activity by using below code...
Activity activity = Robolectric.setupActivity(MyActivity.class);
To get the app context, just call activity.getApplicationContext().
EDIT1: If you're using the latest Robolectric version, use
Robolectric.buildActivity(DashboardActivity.class) instead.
EDIT2: Make sure your SDK1 extends MultiDexApplication". Add this #Config(manifest=Config.NONE, application = App.class, sdk = 17)` to
the top of your test class.
Let me know if it works.
I am doing the unit testing on android studio, I create a test case in test class and on every time when I run that it give different output but when I debug it give me fine out put.It may be problem of caching or something else. I have also tried Invalidate studio and clean project but still occurring. Please Help.
In your #Before method, make sure to use Intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) to make sure the app is not already running in the background of your test when you begin testing. This could be what is introducing your cache issue.
to clarify, your #Before method should look something like this:
#Before
public void setup() {
//Initialize UiDevice instance
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
mDevice.pressHome();
Intent intent = new Intent("com.REDACTED.auto.diagnostics.dealer.MAIN");
intent.setClassName("com.REDACTED.auto.diagnostics", "com.REDACTED.auto.diagnostics.dealer.MainActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Context context = InstrumentationRegistry.getContext();
context.startActivity(intent);
}
There are simpler ways to do this if you have the source code, however in my case I did not
android studio 2.1. preview 4
I am creating a junit4 unit test to test for opening a file contained in the raw directory.
However, everytime the code runs I can a null pointer from openRawResource.
This is the function I am trying to test. This works when running on the actual device. But not in the unit test.
public String getNewsFeed(Context mContext) {
InputStream inputStream = mContext.getResources().openRawResource(R.raw.news_list); // Null pointer
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferReader = new BufferedReader(inputReader);
int n;
while ((n = bufferReader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
inputStream.close();
}
catch (IOException ioException) {
return "";
}
return writer.toString();
}
This is my test case
#RunWith(MockitoJUnitRunner.class)
public class NewsListPresenterTest {
#Mock
private Context mContext;
#Mock
private NewsListPresenter mNewsListPresenter;
#org.junit.Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNewsListPresenter = new NewsListPresenter(mContext);
}
#org.junit.Test
public void testLoadNewsFeed() throws Exception {
assertNotNull(mNewsListPresenter.getNewsFeed(mContext));
}
}
Many thanks for any suggestions,
You are confusing the two types of unit tests in Android. This is not clear for many people so I'll explain it here.
Why it works on a device: Because this is an instrumented test.
What is an instrumented test? A test that runs on a real device/emulator and the test code is in the 'src/androidTest' folder.
Why it doesn't work as a local junit test: Because local junit tests are not instrumented tests. Local Junit tests run on your computer's JVM, not on the device. Local Junit tests shouldn't contain/use Android code because the real Android code is on the device/emulator, not on your computer's JVM.
I suppose you want to make it run as a junit test to run it faster, and that's why I suppose you moved your test to the 'src/test' folder and context.getResources() is throwing a NullPointerException.
I think you have 2 options here:
Use Robolectric to run this test as a junit test
Refactor your method so it doesn't depend on Android's classes
For option 2, this is what I would do. Change the method's argument to an InputStream:
public String getNewsFeed(InputStream inputStream) {... use inputStream... }
Now your method doesn't see any Android code and you can test it as a normal junit method. You could then pass a fake inputStream to your method, like this:
#Test
public void testLoadNewsFeed() throws Exception {
String fileContents = "line one";
InputStream inputStream = new ByteArrayInputStream(fileContents.getBytes());
assertNotNull(mNewsListPresenter.getNewsFeed(inputStream));
}
If you still want to pass the same inputStream as you're using in your app (I wouldn't recommend it) you still can do it using this code in the test:
#Test
public void testLoadNewsFeed() throws Exception {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("raw/news_list");
assertNotNull(mNewsListPresenter.getNewsFeed(inputStream));
}
And you'll have to add this line to your build.gradle file:
sourceSets.test.resources.srcDirs += ["src/main"]
Android unit tests can be very confusing. You can read about these concepts in this blog post that I wrote
You have to tell the mContext mock what to do when getResources() is called on it.
when(mContext.getResources()).thenReturn(some_mock_of_Resources);
If you don't specify anything, the mock will return null.
For your example, this means you'll probably also need a Resources mock, and also tell it when to do/return when openRawResource() is called on that.
You have created a mock Context so you have to stub the methods used by the method under test.
In getNewsFeed your are using Context::getResources so in your test before invocation of getNewsFeed, you should have:
Resources resoures = ...
when(mContext.getResources()).thenReturn(resources);
The Mockito documentation of stubbing is pretty clear.
In your test, you have also some problems. I think that they have no consequences but they tend to show that you are discovering Mockito.
You wrote:
#Mock
private NewsListPresenter mNewsListPresenter;
Annotates the field with #Mock, tells to mockito to create a mock of NewsListPresenter which the class under test. (Not a big problem since your creating the real instance in the setUp). You could have a look to #InjectMocks (even if i am not a big fan of it).
Another point is that you use both #RunWith(MockitoJUnitRunner.class) and
MockitoAnnotations.initMocks(this), you could avoid the last one since it is invoked by the runner. Furthermore, the runner is a better choice since it validate framework usage.
My last observation, is on your design. May be it is an android constraint, but you are injecting the context both in the presenter constructor and the getNewsFeed method, this seems weird and could leads to inconsistant situation. I would choose the constructor injection (more object oriented design).
Another way to ease testing could be to extract the major parts of the method in an utility class and test the different branches (null stream, empty stream, valid stream, IOException...) without the need of mocking a context and resources:
class IOUtils {
static String readFromStream(InputStream inputStream) {
....
}
}
Note that guava provides a similar utility.
I'm trying to carry out junit test for the Android-DDP library.
To initialize the meteor object, we need a reference to a android context which I'm able to achieve using Robolectric. But the web-sockets is probably talking to the server on a different thread because of which the callback methods are not called and the test methods are getting end.
I used netstat to check if the android client is trying to communicate or not. It shows various ping/pong messages. So, Yes it is trying to talk to the server.
I went through this tutorial as well,
Android AsyncTask testing with Android Test Framework. This one tells how to handle the network on UI thread. But nothing seems right.
The sample code, I have worked is:
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
#RunWith(RobolectricGradleTestRunner.class)
public class MainActivityTest {
private MainActivity activity;
private Meteor meteor;
private String globalUrl = "ws://10.0.3.222:3000/websocket";
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class);
meteor = new Meteor(activity, globalUrl);
meteor.reconnect();
/*
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
}
#Test
public void validateMeteorIsConnected() {
assertTrue(meteor.isConnected());
}
}
Any help would be appreciable. Thanks in advance.
You defined two methods, setup() and validateMeteorIsConnected(), but where are they called?
First, your setup is not correct. After your call to new Meteor(...), you don't need the reconnect() call because the constructor does already establish the connection.
Moreover, you must set up a listener so that you know when the connection has been established or data comes in. This is done with mMeteor.setCallback(...); where the parameter is this or activity.
As you said, the work is done on a different thread and everything is asynchronous.
So you can't just call validateMeteorIsConnected() immediately after connecting.
You need some timer, as shown in the question that you linked to.
I am using InstrumentationTestCase to unit test a component of my application.
The component persists data to the internal storage and uses Context::fileList(); to retrieve the persisted files.
I experience the following problem: Using this method in the app (on the device) works perfectly fine. But when I try to (Android-)Unit-Test (also on the Device) with use of InstrumentationTestCase I get a NullPointerException inside the fileList() method. I digged into the android source and found out that getFilesDir() (see source here) returns null and causes this error.
The code to reproduce is the following:
public class MyTestCase extends InstrumentationTestCase
{
public void testExample() throws Exception
{
assertNotNull(getInstrumentation().getContext().getFilesDir()); // Fails
}
}
My questions are: Is this behaviour intended? What can I do to circumvent this issue? Am I using InstrumentationTestCase right or should I use something different?
I found this question but I'm not sure if this covers the same problem I have.
I think that you are right with keeping your test data separate from tested application.
You can fix problem with Null by creating files directory for Instrumentation app by executing the following commands
adb shell
cd /data/data/<package_id_of_instrumentation_app>
mkdir files
You can do above only on emulator or rooted device.
Then test from your question will not fail. I did it and also uploaded file named tst.txt to files dir, all below tests were successful:
assertNotNull(getInstrumentation().getContext().getFilesDir());
assertNotNull(getInstrumentation().getContext().openFileInput("tst.txt"));
assertNotNull(getInstrumentation().getContext().openFileOutput("out.txt", Context.MODE_PRIVATE));
But I think more convenient way to provide data to test project is to use assets of test project where you can simply save some files and open them:
assertNotNull(getInstrumentation().getContext().getAssets().open("asset.txt"));
or if you want to save some results of tests to the file you can use ExternalStorage:
File extStorage = Environment.getExternalStorageDirectory();
assertNotNull(extStorage);
#Blackbelt mentioned in his comment to use getTargetContext() instead of getContext(). I missed the comment, and after a few hours, of trying to figure out how to Realm.init() from an Android instrumented tests, I find out that I need the Context from getTargetContext()...(along the way, i tried to context.filesDir.mkdirs())
package com.github.ericytsang
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Test
class InstrumentedTest {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
#Test
fun can_mkdirs() {
assert(context.filesDir.mkdirs())
}
}