Robotium - how to run selective test cases? - android

My test class has 3APIs that run three test cases (test***()).
When I run the project as JUnit test case, how stop one or more of these 3 test cases to execute?
Basically, how to selectively run test cases present in the same file? {Putting them in a separate class is not really the solution!! :)}
Rc

If you are using Eclipse and just want to run a single test method instead of the whole suite or the whole test class, you just right click the method-name and choose "Run as.." -> "Android JUnit Test"

To selective skip test cases with JUnit you can add an #Ignore annotation above the test method(s) you don't want to run.

You can also do this from the commandline:
adb shell am instrument -e class com.android.demo.app.tests.FunctionTests#testCamera com.android.demo.app.tests/android.test.InstrumentationTestRunner
In this example, you're running only test method 'testCamera' in class FunctionTests. You can add multiple values via the -e argument.

Since there is no #Ignore annotation in JUnit 3, I had to figure out a workaround to ignore the long-running activity/instrumentation test cases from my test suite to be able to run the unit tests:
public class FastTestSuite extends TestSuite {
public static Test suite() {
// get the list of all the tests using the default testSuiteBuilder
TestSuiteBuilder b = new TestSuiteBuilder(FastTestSuite.class);
b.includePackages("com.your.package.name");
TestSuite allTest = b.build();
// select the tests that are NOT subclassing InstrumentationTestCase
TestSuite selectedTests = new TestSuite();
for (Test test : Collections.list(allTest.tests())) {
if (test instanceof TestSuite) {
TestSuite suite = (TestSuite) test;
String classname = suite.getName();
try {
Class<?> clazz = Class.forName(classname);
if (!InstrumentationTestCase.class.isAssignableFrom(clazz)) {
selectedTests.addTest(test);
}
} catch (Exception e) {
continue;
}
}
}
return selectedTests;
}
}
Simply run this test suite as an Android JUnit test.

Related

How do i relaunch application from start for every individual test case in Espresso Android

I have a testsuite which has mutiple testcases in a class
every test case is isolated
So when i execute the testsuite class i want to restart the app for every testcase
How do i relaunch application from start for every individual test case in Espresso
Thanks in advance
#Test
public void testcase1() {
//from first screen
}
#Test
public void testcase2() {
//from first screen
}
There is another stack overflow answer that seems to answer this question. If you were looking to do that in Kotlin though I converted the answer to relaunch multiple times for different tests.
#RunWith(AndroidJUnit4::class)
class ExampleEspressoTest {
#get:Rule
val rule = ActivityTestRule(
activityClass = MainActivity::class.java,
initialTouchMode = false,
launchActivity = false) //set to false to customize intent
#Test
fun testCustomIntent() {
val intent = Intent().apply {
putExtra("your_key", "your_value")
}
rule.launchActivity(intent)
//continue with your test
}
}
If you need to start a method/test and when it's finished clear data and start the next one, you should use commands.
Look at this documentation: https://developer.android.com/studio/test/command-line
I'm using this command:
./gradlew testVariantNameUnitTest --tests *.sampleTestMethod
There could be several ways to do this but we wanted a way that works both locally as well as google fire base test lab, so ended up with using configuration in build.gradle file under default config.
defaultConfig{
testInstrumentationRunnerArguments clearPackageData: 'true'
}
Reference: https://developer.android.com/training/testing/junit-runner#ato-gradle
Also you use these runner arguments for configuring different tests you wanted run based on build variants or other config options, look at my post if you want more detail.

How to use android.os.Process in junit test?

I'm trying to implement a simple test that uses android.os.Process.myPid (actually I have a large class that uses myPid, but to avoid posting large source I simplified everything down to this):
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class ProcessTest {
#Test
public void testTest() {
assertTrue(true);
}
#Test
public void testPid() {
int pid = android.os.Process.myPid();
//assertTrue(true);
}
}
First test passes ok, but second fails with this error message:
java.lang.UnsatisfiedLinkError: android.os.Process.myPid()I
What's wrong? How to test classes that use android.os.Process?
You can't do that in unit tests. You can't access Android OS packages in unit tests. You can mock them! You want a process id, but there's no OS running (apart from the machine you're developing on).
After a while I found solution for my problem -- instrumentation tests. Well, yes, as Krzysztof Kubicki pointed out, it can't be done in unit tests. But while it's possible to mock things, is difficult in real case. I was able to mock pid for my simple test, but the real thing was AesCbcWithIntegrity by Tozny with all bells and whistles, including things like this:
int bytesRead = (Integer) Class
.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_load_file", String.class, long.class)
.invoke(null, "/dev/urandom", 1024);
This is kinda difficult to mock. So, instead of mocking I created instrumentation test and ran tests on emulator.
And that solved my problem without much effort. Yes, instrumentation tests are slow compared to regular unit testing, but at least it works.

Tell Espresso to run specific tests on an emulator

I have Android instrumentation tests with Espresso. Some of my tests must be run on an emulator - due to using LinkedIn's TestButler (https://github.com/linkedin/test-butler) library. This library toggles wifi/gsm for specific test runs, and that is why these tests must be run on an emulator.
My question is - can I annotate any specific tests to run on an emulator, while having the other tests run on a real device?
Thanks
Yes, you can use a #ConditionalIgnore annotation as described in http://www.codeaffine.com/2013/11/18/a-junit-rule-to-conditionally-ignore-tests/.
You will have something like
public class SomeTest {
#Rule
public ConditionalIgnoreRule rule = new ConditionalIgnoreRule();
#Test
#ConditionalIgnore( condition = NotRunningOnEmulator.class )
public void testSomething() {
// ...
}
}
public class NotRunningOnEmulator implements IgnoreCondition {
public boolean isSatisfied() {
return !Build.PRODUCT.startsWith("sdk_google");
}
}
EDIT
For this specific case of detecting a device or emulator you can also use #RequiresDevice.
The most straightforward solution I found is to use JUnit Assume API: http://junit.org/junit4/javadoc/4.12/org/junit/Assume.html
So, inside the test methods that can only be run on an emulator, I put this code:
Assume.assumeTrue("This test must be run in an emulator!", Build.PRODUCT.startsWith("sdk_google"));
This results in the said test being ignored when it isn't run on an emulator, and a handy error msg in the run window:
As you can see, the other two tests passed fine (in the green), and the entire test suite was able to run.

junit4 opening a getResources().openRawResource using mockito runs nullpointer

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.

Is there a way to set a build config field for Espresso tests (or something similar)?

I'm working on automated testing in Android, and I'm trying to figure out a way to determine - in code - if it's being executed via Espresso or not. I've come across the following:
ActivityManager.isRunningInTestHarness()
but that doesn't work. Is there something similar I can do? Is there a way to add a buildConfigField for an Espresso test in build.gradle?
One way to reliably find out whether your app is running instrumented by your test suite is to try to load a test suite class:
private boolean isInstrumentedRun() {
boolean result;
try {
getApplication().getClassLoader().loadClass(
"my.fully.qualified.TestProjectClass");
result = true;
} catch (final Exception e) {
result = false;
}
return result;
}

Categories

Resources