In our current framework we have a base class that extends ActivityInstrumentationTestCase2 | Android Developers. Typically when we write our test case classes we inherit this base class ( lets call it FooBase) and write our methods. As you can imagine this is getting really big and I would like to refactor it so that for each area of the feature we are testing it is in its own class so that we can reuse it. Hopefully my vague classes are accurate enough The goal is just being able to split the methods into different classes and call them from my testcase
public class FooBase extends ActivityInstrumentionTestCase2 {
#Override
public void runTestOnUiThread(Runnable runnable) {
try {
super.runTestOnUiThread(runnable);
} catch (InterruptedException e) {
throw RuntimeInterruptedException.rethrow(e);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
and our test would be eg
public class TestFooBase extends FooBase{
public void testfeature(){
//execute a method that uses super.runTestOnUiThread()
}
}
How I attempted to refactor it
public class FooHelper extends FooBase{
public FooHelper(Activity activity){
setActivity(activity)
}
public void sameMethod(){
//moved the method in FooBase to this class that uses the runTestOnUiThread
}
}
My new testcase would look something like this
public class TestFooBase extends FooBase{
FooHelper fooHelper;
public void setup(){
fooHelper = new FooHelper(getActivity);
}
public void testfeature(){
//execute a method that uses super.runTestOnUiThread()
fooHelper.callthemethod()
}
}
When I execute this I get a null pointer on the super.runTestOnUIThread.
You can pass in the entire test class and set up a constructor for it.
public class BaseTestCase {
private Instrumentation instrumentation;
private InstrumentationTestCase instrumentationTestCase;
public BaseTestCase(InstrumentationTestCase testClass, Instrumentation instrumentation){
this.instrumentationTestCase = testClass;
this.instrumentation = instrumentation;
}
public Activity getCurrentActivity() {
try {
instrumentationTestCase.runTestOnUiThread(new Runnable() {
#Override
public void run() {
//Code
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return activity;
}
To use, you want to instantiate the BaseTestCase class on the setUp method
public class ActivityTest extends ActivityInstrumentationTestCase2<TestActivity.class>{
private BaseTestCase baseTestCase;
#Override
public void setUp() throws Exception {
super.setUp();
getActivity();
baseTestCase = new BaseTestCase(this, getInstrumentation());
}
}
And to access the public methods in your BaseTestCase
public void testRun(){
baseTestCase.getCurrentActivity();
}
Related
Hello everyone I've been struggling to understand how to inject a listener to a main activtity with Dagger2, I wonder if what I'm trying to do is possible or even a right move with dagger or should I just let it like it is right now I have read that I need to create another class with the implementation of that interface but is not possible(or recommended) to inject on the mainactivity?, thanks in advance to anyone who can help me, I have everything in short as follows:
//////////////////////////////////////MainActivity.class//////////////////////////////////////
public class MainActivity extends AppCompatActivity implements CustomListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//this is the object I want to inject in Dagger
LongProcess longProcess = new LongProcess(this);
longProcess.longRunningProcess();
}
#Override
public void onProcessStarted() {
Log.i(TAG, "onProcessStarted: CALLBACK!");
}
#Override
public void onProcessFailed() {
Log.e(TAG, "onProcessFailed: CALLBACK!");
}}
//////////////////////////////////////LongProcess.class//////////////////////////////////////
public class LongProcess {
private CustomListener customListener;
public LongProcess(CustomListener customListener) {
this.customListener = customListener;
}
public void longRunningProcess() {
try {
//some long process started...
customListener.onProcessStarted();
} catch (Exception e) {
//some long process failed...
customListener.onProcessFailed();
}
}
}
//////////////////////////////////////interface.java//////////////////////////////////////
public interface CustomListener {
void onProcessStarted();
void onProcessFailed();
}
You can take a look at Assisted Injection for this use case: https://dagger.dev/dev-guide/assisted-injection
I have the following AsyncTask class which I want to handle multiple api calls and return a List back to my activity. I am having a problems trying to make this work.
How can I return an object back to my activity when onPostExecute() method does not return anything?
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
}
}
One of the options is to create interface and use as callback.
In async task class :
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
public interface NetworkCallback{
void onResponse(List<Students> students);
}
private NetworkCallback callback;
public void setCallback(NetworkCallback callback){
this.callback = callback;
}
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
callback.onResponse(students)
}
}
and now in your activity implement the interface and provide to the async task via setter.
public class StudentsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.... you setup for activity
NetworkCall networkCall = new NetworkCall();
networkCall.setCallback(new NetworkCall.NetworkCallback() {
#Override
public void onResponse(List<Students> students) {
//update your UI here
}
});
}
}
Based on the Docs onPostExecute runs on the main UI thread so no need to the runOnUiThread and Runnable
you can implement like this:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted(Object o);
}
Your Activity:
public class YourActivity implements OnTaskCompleted{
// your Activity
#Override
void onTaskCompleted(Object o){
}
And your AsyncTask:
public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object
to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted listener){
this.listener=listener;
}
// required methods
protected void onPostExecute(Object o){
// your stuff
listener.onTaskCompleted(o);
}
}
I'm trying to implement an Observer/Subscriber with RxJava for the first time.
I get the compile error:
cannot resolve method subscribe(android.support.v4.app.Fragment)
on the line indicated below. So I'm not subscribing correctly.
How do I do this?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Fragment myFragment = mTabsPageAdapter.getItem(2);
Observable<String> loadAndStoreDataObservable = Observable.create(
new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
try {
<get data from RESTful service>
<write data to SQLite db on device>
subscriber.onNext("Done");
subscriber.onCompleted();
}
catch (Exception e) {
subscriber.onError(e);
}
}
}
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(myFragment); // cannot resolve method subscribe(android.support.v4.app.Fragment)
}
}
import android.support.v4.app.Fragment;
public class MyFragment extends Fragment implements Observer<String> {
#Override
public void onNext(String s) {
System.out.println(s);
}
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
}
Edit: I changed the line suggested by Vladimir Mironov. This seems to be necessary but not sufficient. Implementing it I then get a compile error on the line after that:
Incompatible types: Required rx.Observable
Found rx.Subscription
It suggests casting to (Observable<String>) like so:
Observable<String> loadAndStoreDataObservable = (Observable<String>) Observable.create(...)
which does indeed compile error-free, but gives the runtime error:
java.lang.ClassCastException: rx.observers.SafeSubscriber cannot be cast to rx.Observable
Edit 2:
I think it should be: Subscription loadAndStoreDataObservable = ...
No one is stepping forward, so I'll aggregate the comments into an answer.
Cast to MyFragment:
MyFragment myFragment = (MyFragment) mTabsPageAdapter.getItem(2);
Change loadAndStoreDataObservable to be a Subscription
Subscription loadAndStoreDataObservable = ...
In OnDestroy(), unsubscribe:
protected void onDestroy() {
super.onDestroy();
if (loadAndStoreDataObservable != null) {
loadAndStoreDataObservable.unsubscribe();
}
}
I am a robotium user now switching to Espresso can anyone tell me how to write tests using apk in espresso, as we do in robotium without having acccess to the code but using app apk.
And how to access views without R.id.viewid in espresso? as we do in robotium
solo.getview("viewidText")
In robotium this is how we do
public class CoreTest extends ActivityInstrumentationTestCase2 {
private Solo solo;
//class name of the app launcher activity
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.rex.binderapps.RecorderActivity";
private static Class<?> launcherActivityClass;
static {
try {
launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
#SuppressWarnings("unchecked")
public CoreRecordingTest() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation());
Test.setup(this);
getActivity();
}
#Override
public void tearDown() throws Exception {
solo.finishOpenedActivities();
super.tearDown();
}
...
In espresso
#RunWith(AndroidJUnit4.class)
public class MainActivityTest {
// RecorderActivity is not accessible
#Rule public final ActivityRule<RecorderActivity> main = new ActivityRule<>(RecorderActivity.class);
#Test
public void launchMain(){
}
}
How to specify the class name?
You can use the same reflection technique to specify the class in ActivityTestRule:
#RunWith(AndroidJUnit4.class)
public class MainActivityTest {
private static final String CLASSNAME = "com.rex.binderapps.RecorderActivity";
private static Class<? extends Activity> activityClass;
static {
try {
activityClass = (Class<? extends Activity>) Class.forName(CLASSNAME);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
#Rule
public final ActivityTestRule<?> activityRule
= new ActivityTestRule<>(activityClass);
#Test
public void launchMain() {
}
}
I would like to ask assistance for my error. I used robospice-retrofit for my api and I want to get the cache. In my other sample program the I could get the cache and the value but when i used it in the fragment, I always have a null value of my cache. Btw, I created another class that would handle all my request, is there a problem with this?
Please check my codes: This is created from separate class.
public void roboretroGetTempString(final DomainResponseCallback callback,SpiceManager spiceManager){
boolean isHasCache = false;
TestStringRequest graphRequest = new TestStringRequest();
try {
if(spiceManager.isDataInCache(String.class,"graph",DurationInMillis.ONE_MINUTE).get()){
Log.e(TAG,"onRefresh:Has Cache"+spiceManager.getDataFromCache(String.class,"graph"));
}else{
/*Execute if cache has expired*/
Log.e(TAG,"onRefresh:No Cache");
spiceManager.execute(graphRequest, "graph", DurationInMillis.ONE_MINUTE, new RequestListener<String>() {
#Override
public void onRequestFailure(SpiceException spiceException) {
spiceException.printStackTrace();
callback.onApiResponse("Error", null);
}
#Override
public void onRequestSuccess(String str) {
Log.e(TAG,"onRequestSuccess:result-"+str);
}
});
}
} catch (CacheCreationException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (CacheLoadingException e) {
e.printStackTrace();
}
}
This is the code in my Fragment: DomainResponseCallback is my callback interface. I also passed the SpiceManager as a parameter that I used in the code above.
private void roboLoadTest(){
GraphController graphController = new GraphController();
graphController.roboretroGetTempString(new DomainResponseCallback() {
#Override
public void onApiResponse(String result, Object obj) {
progressBar.setVisibility(View.GONE);
Log.e(TAG,"onApiResponse-"+result);
}
#Override
public void onApiError(String error) {
Log.e(TAG,"onApiResponse-"+error);
}
},getSpiceManager());
}
This is How I set up my Fragment based on the Sample Code and extends my Fragment to this.
public class RoboFragment extends Fragment{
private String TAG = RoboFragment.class.getSimpleName();
/***
* With {#link com.octo.android.robospice.UncachedSpiceService} there is no cache management. Remember to declare it in
* AndroidManifest.xml
*/
private SpiceManager spiceManager = new SpiceManager(RoboSpiceService.class);
#Override
public void onStart() {
super.onStart();
spiceManager.start(getActivity());
}
#Override
public void onStop() {
// Please review https://github.com/octo-online/robospice/issues/96 for the reason of that
// ugly if statement.
if (spiceManager.isStarted()) {
spiceManager.shouldStop();
}
super.onStop();
}
protected SpiceManager getSpiceManager() {
return spiceManager;
}
}
This is my TestRequest`
public class TestStringRequest extends RetrofitSpiceRequest<String,RetrofitApi> {
public TestStringRequest() {
super(String.class, RetrofitApi.class);
}
#Override
public String loadDataFromNetwork() throws Exception {
return getService().getTestRetrofit();
}
}
My RetrofitApi
#GET(api_reciever+"mytestretrofit")
public String getTestRetrofit();
I don't have any idea on whats missing on my code.
Looking forward for your assistance.
A new spice manager is created/started every time a new fragment is open and that spice manager also will close. That is why you will have an empty/null cache. Check this [post].1
In my scenario, I just created a singleton extends with application and created that spicemanager in my main activity(the parent of the fragments). And It works. I don't know if this is the best solution, still searching for more better approach.
public class AppSingleton extends Application{
private static AppSingleton ourInstance = new AppSingleton();
private SpiceManager spiceManager= new SpiceManager(RoboSpiceService.class);
public static AppSingleton getInstance() {
return ourInstance;
}
public SpiceManager getSpiceManager() {
return spiceManager;
}
}