Calling findViewById() in Junit test - android

I an new to unit testing and I have a simple test method that isnt working. Here is what I have:
#Test
public void testLayoutAvailable() {
View v = mMainActivity.findViewById(R.layout.main_activity);
assertNotNull(v);
}
My problem is v is always null. I stepped through the code and mMainActivity is not null and the rest of my test methods all work fine. So I'm sure there is something simple that I'm just not aware of yet. I checked my imports and I also tried com.packagename.R.layout.main_activity and that also returns null. However the app its self works fine, so I know the layout is there and this test should pass.
Any suggestions?????

When you run normal JUnit tests on Android, the rest of the application isn't fully constructed.
However Android provides some helper classes which construct enough of the application such that you are able to test it. Take a look at http://developer.android.com/tools/testing/activity_testing.html
I have mostly used ActivityInstrumentationTestCase2 in the past.

I found out the problem was I was passing in a layout not an id to findViewById().

Related

Understanding results of Android Espresso instrumentation test

I've created a simple test using Espresso in Android Studio.
The test runs to completion and gives a success message.
However, I'm testing to see if two Button views are visible or not.
I expect to see that one button is visible and the other is not
The test result does not mention this at all. The goal of this test is to run it via Firebase Test Lab on various virtual and real devices and read the results of the test!
Here is the simple test on Android Studio:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class MyGraphingTest {
#Rule
public ActivityScenarioRule<MainActivity> activityRule
= new ActivityScenarioRule<>(MainActivity.class);
#Test
public void MyTestMethod(){
//some test instructions that will lead me to where the two Button views are...
//more test instructions that will hide one Button view from screen, while the other Button view remains visible.
onView(withId(R.id.recenter)).check(matches(isDisplayed()));
onView(withId(R.id.buttonGraph2)).check(matches(isDisplayed()));
}
}
see the attached picture to see the test results!
All checks "returned" true, so your test is passed. Otherwise, test will fall and you will see the reason of the failure. If you want to see additional information about your checks, you should add some logs mannualy.
However, I'm testing to see if two Button views are visible or not. I expect to see that one button is visible and the other is not
Your test, as you posted it, is looking for both views to be displayed. Keep in mind that visible means View.VISIBILITY == VISIBLE. Displayed means you could actually see it in the current screen. Thus a visible view may not actually be displayed if it's off screen or has a zero width or height.
If you actually want to test visibility, you should use withEffectiveVisibility instead of isDisplayed.
The test result does not mention this at all.
You're testing that both views are displayed and the test passes. What do you expect the test to "mention"? Since your test passed, all the assumptions that are in the test held true and the test result has nothing more to tell you.

Android Unit Test + DecimalFormat

I have a method that formats a number, and I wanted to test it.
I built a test calling this method and the result showed that: decimalFormat.setRoundingMode(\* Any rounding mode \*);
doesn't work. It always takes the default RoundingMode.HALF_EVEN.
My method works fine - decimalFormat.setRoundingMode(RoundingMode.HALF_UP); do work when running the app (I copied the test to the app and logged it..)
Why can't I call decimalFormat.setRoundingMode() in a unit test?
Please post your code. Replace the RoundingMode.HALF_UP value with its hard coded primitive value (the value behind it).The static call to RoundingMode might be the cause of this.
It also seems to me that your unit test is wrong, you're checking a behavior of a class based on an existing implementation of your dependency (decimalFormat). You should never do this in an unit test instead you have to mock decimalFormat away and test the behavior of your method independently from the implementation of 'decimalFormat' or any other dependency.

Avoid a block of code to run during unit test using mokito

I am using Mokitio in android to run unit test cases.
.
What i am trying to do: There is a block of code in onCreate event
of the activity
I am trying not to run this block of code during Running Unit test
cases and run it during app regularly.
Is it possible to do something like that using mokito because mokito synchronizes for activity life cycle
The proper solution here is to change your design a bit. You should not think in terms of code blocks, but in terms of functionality.
The way of preventing that some x lines of code are run in a certain environment, but are not in some other context ... is by using proper OO means.
Meaning: first create an interface that describes the functionality of those lines of code we are talking about:
public interface DoTheFoo {
public void foo(Bar bar);
}
Then you create a "production" implementation DoTheFooImpl of that interface (which as a side effect: you might be able to write proper unit tests for as well).
Finally: within your class that needs that functionality, use dependency injection to acquire an object providing the DoTheFoo interface. In your production environment, that would be a DoTheFooImpl object; but for your unit testing, you would simply create an mock for it - configured to do nothing upen calls to foo().
Of course that sounds like a bit of work; but the point is: currently, your design is somehow deficient. And instead of trying to go for dirty hacks/workarounds, consider looking at your design to identify a more elegant way to resolve your problem.

Rendering issues: The following classes cannot be instantiated

I am converting a Eclipse project to work in Android Studio and have got all issues fixed except some layout xmls are showing the following issue in the drag and drop view
Rendering issues: The following classes cannot be instantiated
X.X.X.myclass.
I checked my class and it seems ok, i changed the latest API i have from the little dropdown; 22 (i guess this is the compile API). I havnt changed my Gradle setup, could it be something in there?
I havnt posted any code as im not sure what would be helpful - any ideas?
First of all: that's just a layout preview. You can edit the XML and carry on with your project and it won't affect anything on it.
The layout rendering thing literally runs your Java classes to create the preview with some mocked implementation or an actual android device, similar to testing mocked implementations.
So this message is just telling you that this mocked system failed to render the preview.
But if you really want to see the preview, you must check where in your class are you relying on variables, or objects that are inherent from your app that the mock system will not have access to.
An example, if your custom view does some special stuff during onLayout:
#Override onLayout(...){
int value = MyLayoutDetailsCalculation.getExtraPadding(getContext());
}
that is a code that is calling to a static method on a separate class that is using the context (probably getting values from system resources or from the display manager) and this will not execute well in a mocked environment and the preview wouldn't be able to render it.
luckly it's an easy fix:
#Override onLayout(...){
int value;
if(isInEditMode()){ // that returns true if this code is being executed by AndroidStudio mocked system.
value = 0; // any value that makes OK for your custom class to properly show a preview
} else {
value = MyLayoutDetailsCalculation.getExtraPadding(getContext());
}
}

Unittesting AsyncTaskLoader with getLoaderResultSynchronously

I am trying to create unit tests for a REST client that does some API calls. The client works fine in the live application, but I can't get it to run in the test case.
Apparantly, LoaderTestCase.getLoaderResultSynchronously() could be used here (at least according to Android reference, but it will not accept my loader. The code:
public void testGetEventInfo() {
// Init some vars
...
// Create & execute loader
RESTLoader loader = new RESTLoader(getContext(),
RESTLoader.HTTPVerb.GET, action, params, LOADER_GET_NEWS);
getLoaderResultSynchronously(loader);
}
This yields the error getLoaderResultSynchronously(Loader) in the type LoaderTestCase is not applicable for the arguments (RESTLoader).
RESTLoader extends AsyncLoader. Note that I'm using the supportlibrary, maybe the Loader in there is incompatible? The documentation gives no information on this.
I've tried to solve this in several ways, though none seem to work:
Registered a listener to loader. However, the callback never triggers
Using CountdownLatch (also with a listener). Again, no trigger/countdown timeout.
Playing around with the type template (), without success.
Similar solutions on SO, though again failing to reach the listener.
Does anybody know why getLoaderResultSynchronously will not accept the loader? Or another clean way of testing the Loader, including a way to test return data? I can test handling the return data in a separate case, but I would also like to test the actual data.
Sincerely,
Have you taken a look at the source code? You'll find the following import statements:
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
It doesn't look like Android offers a support version for LoaderTestCase. The easiest solution would be to temporarily change to the non-support LoaderManager (that is, have your class make use of the android.content.Loader instead), test your app, and then switch back to the support implementation. You might also consider copying the testing source code into your project, import the support LoaderManager, and execute it directly. I'm not familiar with the test libraries for Loaders but it doesn't seem outwardly obvious that this would cause any major issues.
You can get sources from LoaderTestCase here, create SupportLoaderTestCase class from that sources in your test project and modify all namespaces to support library namespaces (e.g. change android.content.Loader with android.support.v4.content.Loader). Than you can extend your test case from SupportLoaderTestCase (not from LoaderTestCase) and use it without problems
The method you are trying to call (getLoaderResultSynchronously) accepts an object of type android.content.Loader. If your RESTLoader class is not of that EXACT type then you will get this error. I suspect your class directly or indirectly extends android.support.v4.content.Loader, which would explain the error.
I am not aware of a back-port of LoaderTestCase that would support testing of this type of class.

Categories

Resources