I'm new to using the Roboelectric testing framework and the issue that I am having is not being able to build an activity. I used the same exact test in every class and they worked as expected, except for the CallingActivity that relies on being called by Handler.postDelayed which I believe is the problem.
This is the code that will create the CallingActivity:
btnCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Handler().postDelayed(new Runnable()
{
#Override
public void run() {
Intent intent = new Intent(FakePhoneCallMenuActivity.this, CallingActivity.class);
intent.putExtra("callerName", nameEntryBox.getText().toString());
intent.putExtra("callerPhoneNum", phoneEntryBox.getText().toString());
intent.putExtra("callerVoice", voice);
startActivity(intent);
}
}, timeToStart);
}
});
This is test for the CallingActivity that is having issues working:
#RunWith(RobolectricTestRunner.class)
#Config(sdk = {Build.VERSION_CODES.O_MR1})
public class CallingTest {
private CallingActivity activity;
#Before
public void setUp() throws Exception {
activity = Robolectric.buildActivity(CallingActivity.class)
.create()
.start()
.resume()
.get();
}
#Test
public void acceptCallButtonClickShouldStartNewActivity() throws Exception {
ShadowActivity shadowActivity = shadowOf(activity);
ImageButton button = (ImageButton) shadowActivity.getContentView().findViewById(R.id.btnAcceptCall);
button.callOnClick();
Intent startedIntent = shadowActivity.getNextStartedActivity();
ShadowIntent shadowIntent = shadowOf(startedIntent);
assertEquals(FakePhoneCallMenuActivity.class, shadowIntent.getIntentClass());
}
}
The issue that I am recieving after trying to run this test is:
java.lang.Exception: Main looper has queued unexecuted runnables.
Help with this would be greatly appreciated!
Thanks
Related
I've created a splash screen in my app that displays for 3 seconds before moving to LogInActivity. It looks like this:
public class SplashScreenActivity extends AppCompatActivity {
// Splash screen displays for 3 seconds.
private static int SplashTimer = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
finishTiming();
}
public void finishTiming() {
Handler h = new Handler(Looper.getMainLooper());
h.postDelayed(new Runnable() {
#Override
public void run() {
// App then transitions to login activity.
Intent intent = new Intent(SplashScreenActivity.this, LogInActivity.class);
startActivity(intent);
finish();
}
}, SplashTimer);
}
}
Now I'm trying to test it and I have two tests. testTimer() checks that the timer works as it should and SplashScreenToLogin() checks that the activity moves to the LogInActivity next:
#RunWith(AndroidJUnit4.class)
public class SplashScreenActivityInstrumentationTest {
SplashScreenActivity splashScreenActivity;
private Instrumentation.ActivityMonitor activityMonitor;
#Before
public void createSplashScreenActivity() {
splashScreenActivity = new SplashScreenActivity();
activityMonitor = InstrumentationRegistry.getInstrumentation().addMonitor(LogInActivity.class.getName(), null, false);
}
#Test
public void testTimer() {
assertFalse(splashScreenActivity.isFinishing());
splashScreenActivity.finishTiming();
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
assertTrue(splashScreenActivity.isFinishing());
}
#Test
public void SplashScreenToLogin() {
splashScreenActivity.finishTiming();
splashScreenActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
LogInActivity logInActivity = (LogInActivity) InstrumentationRegistry.getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 10000);
assertNotNull(logInActivity);
logInActivity.finish();
}
}
My issues is that when I run this I get the following error: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
This error displays at the first line of each test function and I'm not sure why. Can someone explain why it's happening and a potential solution?
hi guys Im having some problems with my frist Testing
im writing this snippet but i keep get this problem:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertNotNull(Assert.java:712)
at org.junit.Assert.assertNotNull(Assert.java:722)
someone know hot to help me? and maybe also which are the correct thing to test in this class? thanks a lot
I already have Junit implementation in gradle
the test class is :
public class QrActivityTest {
public QrActivity tester;
#Before
public void setUp(){
tester = new QrActivity();
}
#Test
public void onCreate() {
//barcodeDetector = new BarcodeDetector.Builder(tester.getApplicationContext()).setBarcodeFormats(Barcode.QR_CODE).build();
// Assert.assertNotNull(barcodeDetector);
Assert.assertNotNull(tester);
Assert.assertNotNull(tester.cameraSource);
}}
the class is:
public class QrActivity extends AppCompatActivity {
SurfaceView surfaceView;
CameraSource cameraSource;
TextView textView;
BarcodeDetector barcodeDetector;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.barcode_scanner_layout);
surfaceView = (SurfaceView) findViewById(R.id.camera);
textView = (TextView) findViewById(R.id.txt);
barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build();
cameraSource = new CameraSource.Builder(this, barcodeDetector).setRequestedPreviewSize(640, 480).setAutoFocusEnabled(true).build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(QrActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
cameraSource.start(holder);
} catch (IOException e) {
Toast.makeText(QrActivity.this, "errore fotoamera", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
//this is to take data
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> qrCodes = detections.getDetectedItems();
if (qrCodes.size() != 0) {
textView.post(new Runnable() {
#Override
public void run() {
Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(300);
textView.setText(qrCodes.valueAt(0).displayValue);
if (qrCodes.valueAt(0).displayValue.equals("129063")) {
Intent intent = new Intent(QrActivity.this, AttrezzaturaRecycleView.class);
startActivity(intent);
Utility.showToast(QrActivity.this, "Dispositivo trovato!");
}
}
});
}
Assertions check internal the values. If the assertion isn't met they throw an exception. So you might check the full stack trace.
The exception probably occur in the line Assert.assertNotNull(tester.cameraSource);. This is caused because cameraSource will be null. This is caused because you only create an instance of the class but no Events like onCreate are called. A simple Unit test isn't enough for front end testing.
You might need an instrumented test case. Pleas try to use the JUnit testrules to instantiate the Activity. Concider that you need a device or emulator to run this tests.
As #finder2 sais, the problem is, that tester.cameraSource is null.
I think, this is because the method onCreate() is never executed.
You may start your Application like normal or run onCreate by using Reflection.
You could also move the necessary code inside the constructor or a public method.
I searched for a solution and couldn't find one so I'll ask here:
I'm trying to use setText command in the mainActivity, Until now I've used:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
textViewPrograss.setText(finalI + "");
}
});
now I'm trying to do the same thing, but from another class so i cant use:MainActivity.this.
I was trying to use code i found on another question with no success,This is the code:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}});
Any suggestions?
This (the second code sample from your question) is the correct way to access UI Thread from random location, although you should always try to have a Context to do this :-)
new Handler(Looper.getMainLooper()).post(
new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}});
It does work, and if it does not, check if you have debug logs enabled in your debugger ^^
You can use this snippet
textView.post(new Runnable() {
#Override
public void run() {
textView.setText("Text");
}
});
Try this just pass the context to other class and then use it like this
((Activity)context).runOnUiThread(new Runnable() {
public void run() {
textViewPrograss.setText(finalI + "");
}
});
I suggest you tu use a BroadcastReceiver in the MainActivity. Register a new receiver with a specific action and send an Intent with that action from "another class". The MainActivity will receive the notification and can edit the TextView content in a clean way
MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// update your text view
String text = intent.getStringExtra("text");
}
};
registerReceiver(mReceiver, new IntentFilter(MY_ACTION));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
Another class:
Intent intent = new Intent(MY_ACTION);
intent.putExtra("text", "Your wonderful text");
// take a context reference (e.g. mContext) if you don't have a getContext() method
getContext().sendBroadcast(intent);
This is my solution (using MVVM, so no business logic in activity), run this in your class (viewmodel in my case):
runOnUiThread(() -> methodToExecute());
here is the method implementation (I have this in my base viewmodel):
private Handler messageHandler;
protected void runOnUiThread(Runnable action) {
messageHandler.post(action);
}
Don't forget to init messageHandler:
messageHandler = new Handler(Looper.getMainLooper());
I'm new to android studio.
I've imported project in android studio and without any changes I'm getting the error.
'Class or interface Expected'
Can anyone help me out?
class this.cls0
implements android.view.istener
{
final LyricsEdit this$0;
public void onClick(View view)
{
mDismissMethod = 1;
mLyrics = mEditLyrics.getText().toString();
dismiss();
}
()
{
this$0 = LyricsEdit.this;
super();
}
}
If you would like to handle Click event you should try this:
_loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Some method to do...
}
});
Hope it will help.
I am trying to create a unit test for my main activity.
The MainActivity.class contains an inner static fragment class, in this fragment is a button made from a TextView that launches another Activity in it's onClick method. I get a NullPointerException when I run a unit test. The code for the unit test is:
public class MainActivityTest extends ActivityUnitTestCase<MainActivity> {
private Intent mMainIntent;
private MainActivity mMainActivity;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
mMainIntent = new Intent(Intent.ACTION_MAIN);
mMainActivity = startActivity(mMainIntent, null, null);
}
public void testButtonWithValidPostcode () {
FragmentManager m = mMainActivity.getFragmentManager();
m.executePendingTransactions();
TextView mainButton = (TextView) mMainActivity.findViewById(R.id.mainButton);
EditText textField = (EditText) mMainActivity.findViewById(R.id.mainPostcode);
textField.setText("SE18");
mainButton.performClick();
Intent i = getStartedActivityIntent();
assertNotNull(i);
assertTrue(isFinishCalled());
}
}
It crashes on the performClick() and when in the onClick method when running in debug mode it appears as though the Activity hasn't properly instantiated.
Does anyone know why this happens?
Here is the log output from the test:
java.lang.NullPointerException
at android.app.Activity.startActivityFromFragment(Activity.java:3957)
at android.app.Activity.startActivityFromFragment(Activity.java:3932)
at android.app.Fragment.startActivity(Fragment.java:1054)
at android.app.Fragment.startActivity(Fragment.java:1033)
at com.intuitivedesigns.restaurants.MainActivity$PlaceholderFragment$2.onClick(MainActivity.java:106)
Here is the onClick method in MainActivity.class line 106 is startActivity(intent);
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String postCode = textField.getText().toString();
if (postCode != null && SupportUtilities.isValidPostcode(postCode)) {
Intent listViewIntent = new Intent(MainActivity.this, RestaurantListActivity.class);
listViewIntent.putExtra(POSTCODE_FLAG, postCode);
startActivity(listViewIntent);
}
}
}