android test fixtures - android

I am working on an android app and I have created a new test project for unit tests. Where's recommended to store the test fixtures (like xml files and the like) and what's the proper way to access it ?

It depends if you really mean unit test or instrumented tests (like using espresso and stuff)...
Unit tests:
Put your fixtures in src/test/resources (so e.g. src/test/resources/fixture.json)
Access them from your test classes e.g. using:
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("fixture.json")
Instrumented tests:
Put your fixtures in src/androidTest/assets/ (so e.g. src/androidTest/assets/fixture.json)
Access them from your test classes e.g. using:
InputStream is = InstrumentationRegistry.getContext().getResources().getAssets().open("fixture.json")
Here are some examples of how you can convert InputStream to String.
Here's a pretty good post describing different cases.
P.S. I know this question is 6+ years old... answering for any future searches.

After some searching I found there is no one proper way to store fixtures in Android (also not so much in java either).
Fixtures are a way to provide easy and consistent data to be passed into test cases. Creating .java classes with static methods that return objects is one way to go.
Example:
public class Pojos {
public static List<TaskListItem> taskListItems() {
return Arrays.asList(
new TaskListItem("one"),
new TaskListItem("two"),
new TaskListItem("three")
);
}
}

You can configure Gradle to read resources from a shared folder, you will be able to share code and resources either in unit test or instrumented test by doing the following.
android {
// ...
sourceSets {
final String sharedJavaDir = 'src/sharedTest/java'
final String sharedResourcesDir = 'src/sharedTest/resources'
test.java.srcDirs += sharedJavaDir
test.resources.srcDirs += [sharedResourcesDir]
androidTest.java.srcDirs += sharedJavaDir
androidTest.resources.srcDirs += [sharedResourcesDir]
// ....
}
// ...
}
Let's imagine that I setup a shared test resource in
/app/src/sharedTest/resources/test_fixture_file.txt
Kotlin code
In a UnitTest or Instrumented test you can use.
val resource: InputStream? = this.javaClass.getResourceAsStream("/test_fixture_file.txt")

Related

Is it possible to write parameterized android espresso UI test?

When writing android espresso UI test, is it possible to write parameterized test which accepts data from two different json files to add list of items inside the app?
I have seen parameterized tests that take two files and run same test code for junit test but couldn't find any references for android espresso UI test
You can do something like:
#RunWith(Parameterized.class)
public class LoginTest {
#Parameterized.Parameter
public String mUserName;
#Parameterized.Parameter(value = 1)
public String mPassword;
#Parameterized.Parameters
public static Collection<Object[]> initParameters() {
return Arrays.asList(new Object[][]{
{"validUsername", "validPassword"},
{"invalidUsername", "invalidPassword"},
// or other initialization like json file input
});
}
// Tests using mUserName and mPassword
}
Then every Test will run with each element of you parameters array.
Please take a look at the library https://github.com/google/TestParameterInjector , it is very convenient and the next evolution step of JUnit4 Parameterized.

Storing resources for unit and espresso tests

Currently, I'm storing the same resources in
/test/resources/sample.txt //for unit tests
/main/asssets/sample.txt //for espresso tests
can I store them in one place?
If yes, how can I read them in my tests?
Preferably, I would like to open them as the File object, not InputStream.
So, I finally decided that the best solution, in this case, is to store everything in assets folder (in mock flavor).
You can open them from instrumentation test:
activityRule.activity.assets.open("sample.txt")
from unit tests:
private val ASSET_BASE_PATH = "../app/src/mock/assets/"
fun openAsset(filename: String): InputStream {
return FileInputStream(ASSET_BASE_PATH + filename)

How can I mock and test this class?

The follows was the code which I want to test.
public class Demo {
private static final List<Pair<String, String>> mList;
static {
mList = new ArrayList<>();
mList.add(new Pair<>("F0", "T1"));
mList.add(new Pair<>("F1", "T2"));
mList.add(new Pair<>("F2", "T3"));
}
public String getStr(int pos) {
return mList.get(pos).first;
}
}
I was an android developer. I have get some trouble in test and mock the code.I have use mockito.
I have try some code to test it,but the result was not my expect.
1.First try
#Test
public void test(){
Demo demo=new Demo();
assertEquals(demo.getStr(0),"F0");
/**
* java.lang.AssertionError:
* Expected :null
* Actual :F0
*/
}
2.Second try
#Test
public void test() {
Demo demo = mock(Demo.class);
doCallRealMethod().when(demo).getStr(0);
assertEquals(demo.getStr(0), "F0");
/**
* java.lang.AssertionError:
* Expected :null
* Actual :F0
*/
}
Anyone tell me how can I resolve this problem to make demo.getStr(0) == "F0" by call the real method? Thanks!
===========================
Another question relate to it
I have try an another test to test android.util.Pair class, and the result is that "pair.first" was null,.(There are androidTest and test directory,I put it into test package.Did it impact the result?)
import android.util.Pair;
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
public class DemoTest {
#Test
public void test1(){
Pair<String,String> pair=new Pair("First","Second");
assertEquals("First",pair.first);
//pair.first was null,why?
}
#Test
public void test2(){
Pair<String,String> pair= Mockito.spy(Pair.class);
assertEquals("First",pair.first);
//pair.first was null also,why?
}
}
Why the simple code is correct in real android environment,but failure in test?
I had the same problem too. month ago I have problem with TextUtils class too.
I report this to jUnit but they told me the problem is with android package because in unit test environment you don't have access to platform specific classes
for that pair case you can use this package. this works for me
import android.support.v4.util.Pair;
The problem in your first try is, that the public field "first" is actually null.
Is the Pair class the one from the "javafx.util" package or a custom implementation?
Did you forget "this.first = first" or something similar in the constructor of the "Pair" class?
I would also recommend to change the following line:
assertEquals(demo.getStr(0),"F0");
to
assertEquals("F0", demo.getStr(0));
so that the error is printed correctly.
Your second try does not make any sense. What is the point in mocking the class you want to test?
I think the second example has the same problem as the first one. Pair.first is never set. If you fix that, it should also work (untested).
From Google's Android tools website:
"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).
So how can we solve this?
In other words. If you need a default android class to work properly you either have to include it from a separate repository, or implement it yourself.
In the case of Android's Pair class. You can use android.support.v4.util.Pair instead.
To get access to this class, you can include com.android.support:support-compat:27.0.0 in your build.gradle or dependencies file.
If you are not using Gradle, you can copy the implementation of this file and use it in place of the official one. Or you can try and download the .jar file from this older version https://mvnrepository.com/artifact/com.google.android/support-v4/r7 (I have not tested whether it works)
Another approach (based on this) is to create the class in app/src/test/java/android/util/Pair.java and copy the code from the Android implementation.
This way you don't need extra dependencies. (There may be issues related to the implementation changing after you make the copy, but the dependencies may become stale as well.)

Integrating Robolectric and Cucumber

I want to combine both Robolectric and Cucumber (JVM).
Currently I have two classes ActivityStepdefs where two step definitions for activity management are defined.
My second class is RoActivity Where for example an activity is created from it's class name, and where Robolectric will be used.
When I run RoActivityTest using RobolectricTestRunner the test in this class passes, but when I run RunCukesTest (class for running features as junit test) the code from RoActivity is not running as part of Robolectric, i.e. RunCukesTest search for features on my project and match it with a method inside ActivityStepdefs and finally this class will call a method from RoActivity
Is possible to run test with both junit both* runners?
I'm not sure but perhaps it's possible to do something like powermock, using junit rules.
In that case for which one should I have to define the rule?
*Cucumber and Robolectric
My small 5 cents.
Cucumber is mostly used for acceptance tests (correct me if you use it for unit testing) and Robolectric is mostly used for unit testing.
As for me, it is overkill to write cucumber during TDD. And Robolectric is still not android and I would run acceptance tests on real device or at least emulator.
I'am facing the same problem, after some google work, I got a solution:
#RunWith(ParameterizedRobolectricTestRunner::class)
#CucumberOptions( features = ["src/test/features/test.feature","src/test/features/others.feature"], plugin = ["pretty"])
class RunFeatures(val index: Int, val name:String) {
companion object {
#Parameters(name = "{1}")
#JvmStatic
fun features(): Collection<Array<Any>> {
val runner = Cucumber(RunFeatures::class.java)
Cucumber()
val children = runner.children
return children.mapIndexed{index, feature ->
arrayOf(index,feature.name)
}
}
}
#Test
fun runTest() {
val core = JUnitCore()
val feature = Cucumber(RunFeatures::class.java).children[index]!!
core.addListener(object: RunListener() {
override fun testFailure(failure: Failure?) {
super.testFailure(failure)
fail("$name failed:\n"+failure?.exception)
}
})
val runner = Request.runner(feature)
core.run(runner)
}
}
but seems not an pretty solution for me, can somebody help me out these problem:
must explicitly list all feature file path. but cannot use pattern such as *.feature
when failed cannot know which step failed.
parameter can only pass primitive type data,
I've get into cucumber source , but seems CucumberOptions inline Cucumber , I cannot pass it programmatically but can only use annotation .

How do I get access to resources in my test classes when using robolectric

I have made a text file of values that I want to use for testing in res/raw
I want to use them in testing
I am using robolectric
What is the best way of accessing these values?
Thanks
You can access your app's resources via your Application instance. Use ApplicationProvider to fetch it from within a unit test:
// replace 'Application' with your actual class if you use a custom one
ApplicationProvider.getApplicationContext<Application>().resources
Ensure includeAndroidResources is set to true in your build.gradle or your unit tests won't see your resources:
android {
testOptions.unitTests.includeAndroidResources true
}
wooops, I really should do more research before I post questions
robolectric has got resource support https://github.com/robolectric/robolectric
I have done this as :
int resourceId = Robolectric.getShadowApplication().getResources()
.getIdentifier("myaudio","raw", Robolectric.getShadowApplication().getPackageName());
if (resourceId != 0) { // Raw folder contains resource.
assertTrue(true);
} else { // Raw folder doesn't contain resource.
assertTrue(false);
}
Hope this help...!!
Thanks..!!

Categories

Resources