After running this,
App run.
TestMethod1() executed.
App closed.
TestMethod2() executed.
But I don't want the app to be closed (Step3). I want TestMethod2() to be executed after TestMethod1() is done:
App run.
TestMethod1() execute.
TestMethod2() execute.
App close.
--> I also tried with AddAdditionalCapability("NoReset, true") and AddAdditionalCapability("FullReset, False"), which didn't work.
=> I am using Appium.WebDriver(4.3.1) and C#.
[TestClass]
public class Walkthrough
{
private string _appPath = #"PathToMyApp\MyApp.apk";
private AppiumDriver<AndroidElement> _driver;
[TestInitialize]
public void Setup()
{
var appiumOption = new AppiumOptions();
appiumOption.AddAdditionalCapability(MobileCapabilityType.App, _appPath);
appiumOption.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android");
appiumOption.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Pixel 4");
appiumOption.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "12");
appiumOption.AddAdditionalCapability(MobileCapabilityType.Udid, "99171FFAZ000GE");
appiumOption.AddAdditionalCapability(MobileCapabilityType.NoReset, true);
_driver= new AndroidDriver<AndroidElement>(new Uri("http://127.0.0.1:4723/wd/hub"), appiumOption);
}
[TestCleanup]
public void TestCleanup()
{
_driver.CloseApp();
}
[TestMethod]
public void TestMethod1()
{
_driver.FindElement(By.ID("ELEMENT1")).Click();
}
[TestMethod]
public void TestMethod2()
{
_driver.FindElement(By.ID("ELEMENT2")).Click();
}
}
I finally solved the problem by adding [ClassInitialize] and TestContext in Setup method.
Make sure your method is "Static".
[ClassInitialize]
public static void Setup(TestContext testContext)
{
{
var appiumOption = new AppiumOptions();
appiumOption.AddAdditionalCapability(MobileCapabilityType.App, _appPath);
appiumOption.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android");
appiumOption.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Pixel 4");
appiumOption.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "12");
appiumOption.AddAdditionalCapability(MobileCapabilityType.Udid, "99171FFAZ000GE");
appiumOption.AddAdditionalCapability(MobileCapabilityType.NoReset, true);
_driver= new AndroidDriver<AndroidElement>(new Uri("http://127.0.0.1:4723/wd/hub"), appiumOption);
}
}
Related
In my android application I have a screen where I have 3 spinners that need to be
filled from APIs call.
static List<TripCode> tripCodeList = new ArrayList<>();
static List<Fleet> truckList = new ArrayList<>();
static List<Trailer> trailerList = new ArrayList<>();
And I don't want to inflate the layout unless I get the response from all the 3 different API calls so this is what I'm doing
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
if (MyApplication.isConnected()) {
getTripCodes();
} else {
Toast.makeText(this, "No internet Connection", Toast.LENGTH_LONG).show();
setContentView(R.layout.no_internet_connection);
}
}
Basically , I removed setContentView(R.layout.activity_create_trip);
from onCreate() And I called getTripCodes()
here's the code for getTripCodes()
public void getTripCodes() {
MyApplication.showProgressDialog(getString(R.string.please_wait), this);
IMyAPI iMyAPI = MyApplication.getIMyAPI();
Call<List<TripCode>> call = iMyAPI.getTripCodes();
call.enqueue(new Callback<List<TripCode>>() {
#Override
public void onResponse(Call<List<TripCode>> call, Response<List<TripCode>> response) {
if (response.isSuccessful() && response.body() != null) {
tripCodeList = response.body();
Log.d("test", "getTripCodes success = " + tripCodeList.size());
getTrucks();
} else {
MyApplication.dismissProgressDialog();
}
}
#Override
public void onFailure(Call<List<TripCode>> call, Throwable t) {
MyApplication.dismissProgressDialog();
}
});
}
So in the success of the call I'm calling the other function getTrucks() which also get result from API and in the success it will call getTrailers()
But I think it's a waste of time, because I can call the three function all together in parallel, and then check if all the list are filled or not.
But I don't know how to do it. How can I check if all the calls are success? And if one of them has failed, how will I know which one exactly failed?
I Believe for your problem you can easily use Retrofit 2.6.0 which has coroutine support and you can declare all the function's as suspended function's and dispatch them with async/launch dispatcher and if you want to wait for some result in some case use await() to wait for the result.
And use RxJava/liveData for responsive UI
sample code for you will look like
//maybe from Activity for ViewModel you can use ViewModelScope
GlobalScope.launch{
result1= async{ getTripCodes() }
result2= async{ getTrucks() }
result3= async{ getTrailers() }
doSomethingWithTripCodes(result1.await())
doSomethingWIthTrucks(result2.await())
doSomethingTrailers(result3.await())
}
Reference:
post1
With API 24 we got a way to dispatch a gesture to the device, however there is no solid documentation or examples out there yet. I am trying to get it to work but currently the gesture is hitting the "onCancelled" callback every time.
Here is my code that calls the method:
#TargetApi(24)
private void pressLocation(Point position){
GestureDescription.Builder builder = new GestureDescription.Builder();
Path p = new Path();
p.lineTo(position.x, position.y);
p.lineTo(position.x+10, position.y+10);
builder.addStroke(new GestureDescription.StrokeDescription(p, 10L, 200L));
GestureDescription gesture = builder.build();
boolean isDispatched = dispatchGesture(gesture, new GestureResultCallback() {
#Override
public void onCompleted(GestureDescription gestureDescription) {
super.onCompleted(gestureDescription);
}
#Override
public void onCancelled(GestureDescription gestureDescription) {
super.onCancelled(gestureDescription);
}
}, null);
Toast.makeText(FingerprintService.this, "Was it dispatched? " + isDispatched, Toast.LENGTH_SHORT).show();
}`
Has anyone used this new method yet or know of an example of how to get it functioning?
Your path is just lineTos, which doesn't specify a starting point. Try changing the first one to a moveTo.
What I'm doing: I'm testing an Android aplication using Robotium.
What works: If I have a test in one test method everithing works fine
What doesn't work: If I try do divide this test in to two smaller, then the first test is passing, and the second is hanging (or freezing - I don't know how to name that)
Why I need that I need that to make reports in sppon showing bars for each test (I will have: testLogin, testAddCustomer, testLogout etc). Example of spoon report looks like this:
If i have one big test (testAll) there is only one big green bar, but I need to have many short bars for each test method like on the image above.
What I've done: I have read a lot of different topics about simillar problems but it didn't help me
Here is an short example of what works (one method - testAll()) I wrote currents activities in comments:
public class LogInLogOut extends ActivityInstrumentationTestCase2 {
private Solo solo;
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "mobile.touch.core.activity.SplashScreenActivity";
private static Class<?> launcherActivityClass;
static {
try {
launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public LogInLogOut() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation());
getActivity();
}
#Override
protected void tearDown() throws Exception {
try {
solo.finalize();
} catch (Throwable e) {
e.printStackTrace();
}
getActivity().finish();
super.tearDown();
}
public void testAll() {
// here is LoginActivity <<-----
// username
solo.clickOnView(solo.getView(0x3));
solo.enterText((android.widget.EditText) solo.getView(0x3), "user");
// enter password
solo.clickOnView(solo.getView(0x3, 1));
solo.enterText((android.widget.EditText) solo.getView(0x3, 1), "password");
// click on log in button
solo.clickOnView(solo.getView(android.widget.Button.class, 0));
// here ContainerActivity starts <<-----
//click on log out
solo.clickOnMenuItem("LogOut");
}
}
With the testAll () method all test is passed. But I need to divide that into testLogin() and test testLogout().
here is how I divide metod testAll into two smaller (testLogin() & testLogout()):
public void testLogin() {
// here is LoginActivity <<-----
// username
solo.clickOnView(solo.getView(0x3));
solo.enterText((android.widget.EditText) solo.getView(0x3), "user");
// enter password
solo.clickOnView(solo.getView(0x3, 1));
solo.enterText((android.widget.EditText) solo.getView(0x3, 1), "password");
// click on log in button
solo.clickOnView(solo.getView(android.widget.Button.class, 0));
// here ContainerActivity starts <<-----
}
public void testOut() {
//click on log out
solo.clickOnMenuItem("LogOut");
}
Now first test (testLogin()) is passed and the second (testLogout()) is hanging
To check if the test even started I put log into it.
public void testOut() {
Log.i("checkTestB", "test B started"); <<-- here is the log
//click on log out
solo.clickOnMenuItem("LogOut");
}
It occurse that the testLog is not ececuting the code, becouse "test B started" was not in the log
Question: How can I solve that problem?
I find answer. Method setUp() is perormed before each test method, and tearDown() is performed after each test method. It coused the problem.
I override setUp() and tearDown() with:
#Override
public void setUp() {
}
#Override
protected void tearDown() throws Exception {
if (exit == true) {
try {
solo.finalize();
} catch (Throwable e) {
e.printStackTrace();
}
solo.finishOpenedActivities();
super.tearDown();
}
}
Then I wrote my own mehtods startUp() identical like setUp() and tearDown() deleted.
public void startUp() {
solo = new Solo(getInstrumentation());
getActivity();
}
Then setUp() do nothig when it is performed before test. The same thing is with teadDown() it makes nothing unltil I will set exit==true in test method.
The resolution is to start manulay startUp() in FIRST test method and in the LAST test method exit=ture (default is false), then tearDown() will run and close everything.
Now I manually start activity in testLogin():
public void testLogin() {
startUp(); <<<<<<<-----------------same method as setUp() but can started manually
solo.clickOnView(solo.getView(0x3));
solo.enterText((android.widget.EditText) solo.getView(0x3), "user");
solo.clickOnView(solo.getView(0x3, 1));
solo.enterText((android.widget.EditText) solo.getView(0x3, 1), "password");
solo.clickOnView(solo.getView(android.widget.Button.class, 0));
}
In the second methods testLogout() I use on the begginig: solo = new Solo(getInstrumentation()); and turnDown() method on the end
public void testLogOut() {
solo = new Solo(getInstrumentation());
solo.clickOnMenuItem("LogOut");
exit=true;
}
I have seen plenty of examples of how to use Android TextToSpeak in an Activity, and have also managed to get this to work just fine. I've also managed to get it to work using a bound service in a plugin, but it seems overcomplicated for my purposes. Here is my VoiceService class:
public class VoiceService : IVoiceService, TextToSpeech.IOnInitListener
{
public event EventHandler FinishedSpeakingEventHandler;
private TextToSpeech _tts;
public void Init()
{
// Use a speech progress listener so we get notified when the service finishes speaking the prompt
var progressListener = new SpeechProgressListener();
progressListener.FinishedSpeakingEventHandler += OnUtteranceCompleted;
//_tts = new TextToSpeech(Application.Context, this);
_tts = new TextToSpeech(Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity, this);
_tts.SetOnUtteranceProgressListener(progressListener);
}
public void OnInit(OperationResult status)
{
// THIS EVENT NEVER FIRES!
Console.WriteLine("VoiceService TextToSpeech Initialised. Status: " + status);
if (status == OperationResult.Success)
{
}
}
public void Speak(string prompt)
{
if (!string.IsNullOrEmpty(prompt))
{
var map = new Dictionary<string, string> { { TextToSpeech.Engine.KeyParamUtteranceId, new Guid().ToString() } };
_tts.Speak(prompt, QueueMode.Flush, map);
Console.WriteLine("tts_Speak: " + prompt);
}
else
{
Console.WriteLine("tts_Speak: PROMPT IS NULL OR EMPTY!");
}
}
/// <summary>
/// When we finish speaking, call the event handler
/// </summary>
public void OnUtteranceCompleted(object sender, EventArgs e)
{
if (FinishedSpeakingEventHandler != null)
{
FinishedSpeakingEventHandler(this, new EventArgs());
}
}
public void Dispose()
{
//throw new NotImplementedException();
}
public IntPtr Handle { get; private set; }
}
Note that the OnInit method never gets called.
In my viewmodel I'd like to do this:
_voiceService.Init();
_voiceService.FinishedSpeakingEventHandler += _voiceService_FinishedSpeakingEventHandler;
... and then later ...
_voiceService.Speak(prompt);
When I do this I get these messages in the output:
10-13 08:13:59.734 I/TextToSpeech( 2298): Sucessfully bound to com.google.android.tts
(happens when I create the new TTS object)
and
10-13 08:14:43.924 W/TextToSpeech( 2298): speak failed: not bound to TTS engine
(when I call tts.Speak(prompt))
If I was using an activity I would create an intent to get this to work, but I'm unsure how to do that in a plugin.
Thanks in advance,
David
Don't implement Handle yourself, instead derive from Java.Lang.Object
public class VoiceService : Java.Lang.Object, IVoiceService, TextToSpeech.IOnInitListener
and remove your Dispose() and Handle implementation
More info here: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
Also, I suggest you take an async approach when implementing your service, which would make calling it from view-model something like
await MvxResolve<ITextToSpeechService>().SpeakAsync(text);
I'm trying to make what I thought would be a simple call to a google app engine project.
From a unit test, the call works fine if I access the api directly. I can't do this however, since the call is blocking, so it has to be run from an async task.
What seems to happen is:
A unit test inheriting from ActivityInstrumentationTestCase2 sets up the activity and populates some values
Then I click the button to make the request:
final Button mBet = (Button) mActivity.findViewById(R.id.mybutton);
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mName.setText("blah");
mBet.performClick();
}
});
Then this calls the underlying code to start an async task:
public void bet() throws IOException, InterruptedException {
mMakeTask = new AsyncTask<Void, Void, Model>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
mBetWait = new ProgressDialog(getActivity());
mBetWait.setCancelable(true);
mBetWait.show();
}
#Override
protected Model doInBackground(Void... voids) {
try {
mModel = mController.makeBet(mModel.getBetName(), mModel.getDescription(), mModel.getAnswer(), mModel.getAgainst());
} catch (IOException e) {
e.printStackTrace();
}
return mModel;
}
#Override
protected void onPostExecute(BetModel model) {
super.onPostExecute(model);
Context context = getActivity();
Intent intent = new Intent(context, OtherActivity.class);
intent.putExtra("bet", mModel);
mBetWait.dismiss();
context.startActivity(intent);
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mMakeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
mMakeTask.execute();
}
}
And I forgot to add... when controller is called, it boils down to an appengine call:
public BetInfo makeBet(BetRequest info) throws IOException {
Betrequestendpoint.Builder endpointBuilder = new Betrequestendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Betrequestendpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
BetRequest result = endpoint.insertBetRequest(info).execute();
BetInfo resultInfo = new BetInfo();
resultInfo.setName(result.getName());
resultInfo.setDescription(result.getDescription());
resultInfo.setId(result.getId());
return resultInfo;
}
And to make this more odd... the request call appears to be blocked from the client with the stack trace:
"<13> AsyncTask #2"#831,912,607,944 in group "main": RUNNING
toUpperCase():3266, Character {java.lang}
toUpperCase():3251, Character {java.lang}
toUpperCase():162, CaseMapper {java.lang}
toUpperCase():1548, String {java.lang}
initServiceInfo():152, Services {org.apache.harmony.security.fortress}
getCacheVersion():211, Services {org.apache.harmony.security.fortress}
getInstance():137, Engine {org.apache.harmony.security.fortress}
getInstance():77, KeyManagerFactory {javax.net.ssl}
createDefaultKeyManager():362, SSLParametersImpl {com.android.org.conscrypt}
getDefaultKeyManager():355, SSLParametersImpl {com.android.org.conscrypt}
<init>():111, SSLParametersImpl {com.android.org.conscrypt}
getDefault():146, SSLParametersImpl {com.android.org.conscrypt}
<init>():34, OpenSSLSocketFactoryImpl {com.android.org.conscrypt}
newInstanceImpl():-1, Class {java.lang}
newInstance():1208, Class {java.lang}
getDefault():56, SSLSocketFactory {javax.net.ssl}
<clinit>():114, HttpsURLConnection$NoPreloadHolder {javax.net.ssl}
getDefaultSSLSocketFactory():163, HttpsURLConnection {javax.net.ssl}
copyWithDefaults():363, OkHttpClient {com.android.okhttp}
open():345, OkHttpClient {com.android.okhttp}
open():340, OkHttpClient {com.android.okhttp}
openConnection():28, HttpHandler {com.android.okhttp}
openConnection():479, URL {java.net}
buildRequest():133, NetHttpTransport {com.google.api.client.http.javanet}
buildRequest():68, NetHttpTransport {com.google.api.client.http.javanet}
execute():858, HttpRequest {com.google.api.client.http}
executeUnparsed():410, AbstractGoogleClientRequest {com.google.api.client.googleapis.services}
executeUnparsed():343, AbstractGoogleClientRequest {com.google.api.client.googleapis.services}
execute():460, AbstractGoogleClientRequest {com.google.api.client.googleapis.services}
makeBet():36, BetController {com.chillypixel.youwereright.controller}
makeBet():36, BetApiController {com.chillypixel.youwereright.controller}
doInBackground():129, BetFragment$1 {com.chillypixel.youwereright.bet}
doInBackground():117, BetFragment$1 {com.chillypixel.youwereright.bet}
call():288, AsyncTask$2 {android.os}
run():237, FutureTask {java.util.concurrent}
runWorker():1112, ThreadPoolExecutor {java.util.concurrent}
run():587, ThreadPoolExecutor$Worker {java.util.concurrent}
run():841, Thread {java.lang}
What seems to happen, is I run the test, and it gets to where the progress dialog pops up.
If I then manually interact with the app in the emulator (and hit back or something) the progress dialog goes away and the call completes - then the test passes.
If I just leave it alone though, it appears that the progress dialog just happily spins forever.
Any help would be greatly appreciated.