xunit / devices.xunit

xUnit.net Runners for Devices
Other
73 stars 36 forks source link

Rotating the device resets everything (Android) #28

Open kentcb opened 9 years ago

kentcb commented 9 years ago

The layout is such that test names are not discernible on small devices. The text just gets cut off somewhere within the namespace name, or class name if you're lucky. Also, rotating the device in an attempt to find out test names seems to reset everything.

Perhaps trim the start of the text?

clairernovotny commented 9 years ago

What platform are you seeing the resetting on? Android? There's nothing inherent in the code where a rotate should clear things, but Android is recreates activities and things could be lost

kentcb commented 9 years ago

Yeah, it's Android.

clairernovotny commented 8 years ago

Renaming this as #28 tracks the text size issue itself.

Bowman74 commented 7 years ago

@onovotny Likely what is happening here is a rotation event in Android causes the main activity to reload and is resetting the present state. The likely solution is to save current state on the main activity unload and reconstitute it when the activity reloads.

clairernovotny commented 7 years ago

Almost certainly....pr? :)

Bowman74 commented 7 years ago

I'll take a look at it. ;)

Get Outlook for Androidhttps://aka.ms/ghei36


From: Oren Novotny notifications@github.com Sent: Sunday, February 26, 2017 10:27:51 AM To: xunit/devices.xunit Cc: Kevin E. Ford; Comment Subject: Re: [xunit/devices.xunit] Rotating the device resets everything (Android) (#28)

Almost certainly....pr? :)

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/xunit/devices.xunit/issues/28#issuecomment-282575944, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AELWJqg7GcFWqTuWXmzQQRDSLMkpYjvzks5rgcQngaJpZM4GjaKr.

ToddThomson commented 6 years ago

@onovotny As you likely know, an Android rotation or screen orientation change restarts the currently running Activity. OnDestroy() is followed by OnCreate(). As @Bowman74 mentions above, you must save state to properly handle the Activity restart.

I can issue a PR for this, but I need to determine first how you are handling the background thread that is running the tests. With Android this is accomplished with a Service. I will investigate and get back to you soon...

clairernovotny commented 6 years ago

I'd love a PR to fix this...I've just put up with it all this time. The thing you'd want is to keep the xUnit classes alive between the views and then reattach them to the new view instances. The threading model of the execution doesn't matter as much long as the xUnit class instances are maintained.

ToddThomson commented 6 years ago

@onovotny Yes, I'm just looking into that. When an Activity is destroyed so are all it's resources. It is likely that the thread(s) that is running the test(s) will need to be run in a Service. Let me take a look and I'll get back to you soon...

ToddThomson commented 6 years ago

@onovotny Sorry for the delay. It took me a bit to get debugging working in VS with your library, but I eventually figured it out. I also do not use Xamarin Forms as I find it too much to learn yet another framework. Xamarin.Android and Xamarin.iOS are more of just using c# with the Android and iOS APIs. Each to their own however.

With Android, even though you are using Forms, the entry point to the app is an Activity ( base class for FormsAppCompatActvity - which you should be using to run on a greater API levels set ). This means that android activity lifecycle events occur for various user interactions including device orientation changes. Using Forms does not insulate you from activity life cycle events. When the activity is destroyed so are all it's threads and xunit class instances. The only way to keep background operations running when an activity is torn down is to use a Service.

In general, It is quite likely that running tests may take quite a long time. During this time the user may decide to do anything - switch to, or start, another app, etc. All could cause grief! So, although screen orientations are causing you grief, there are many other user or system interactions that will also cause you grief.

On Android platforms, the way around all these issues is to utilize a background service. You run your test(s) in a service context and utilize a message passing mechanism. This makes your app a bit more complicated. Since your XUnit.Devices package is cross platform you will need to do this for each platform.

I can ( and already have ) made is so that your Android implementation does not allow for tear down of its main activity on screen orientation changes. However, as mentioned above, this will cover only 1 case of user interaction.

This may be outside of the scope of work that want to make. Please give me your thoughts.

clairernovotny commented 6 years ago

I'm not sure I follow 100% -- there's nothing that an activity can do to control/kill the threads we create in our instance...?

If we use a static FormsRunner instance, wouldn't that solve it?

ToddThomson commented 6 years ago

When an Activity is about to be killed it receives the onDestroy() life cycle event. The Activity should then perform housekeeping ( Cancel background threads to avoid avoid memory leaks, etc. ).

A static FormsRunner instance would still live in an Activity context.

Android provides Services to help with background threading scenarios. It's just the way it is. It's not too much more effort to put your DeviceRunner code into a background service.

If using a service is outside the scope of work that you want to make then just clean up your threads when the activity is destroyed and fix screen orientation as portrait.

ToddThomson commented 6 years ago

@onovotny

If we use a static FormsRunner instance, wouldn't that solve it?

I believe you are thinking along the lines of how Xamarin.Android.NUnitLite works. NUnitLite utilizes a static AndroidRunner.Runner instance. This instance will persist until the JVM unloads the outer class or the DVM is killed (essentially). This is perhaps a "Good Enough" solution, but, in general, it is not robust.

If a test app, derived from your RunnerActivity, goes into a paused or stopped state, Android can kill it at any time. Even if the test app is not killed what happens when the test app resumes/restarts? Was a there a test running on a worker thread? Has it completed? Is it still running?

If you don't want your app to save state given life cycle events (how it works now) then I would at minimum make your DeviceRunner static and then have your UI react to its current state (Tests Running, Finished with Results, Not Run, etc ).

The robust approach would be to utilize an Android service to perform the tests and have your UI listen for updates from the service.

This is your package so I just need to know what you're interested in doing ( not much - just deal with the screen orientation change; moderate effort - keep testing state in static DeviceRunner and have the UI react to it's current state; moderate effort - utilize a service component to handle testing with the UI reacting to the state of the service ).

ToddThomson commented 6 years ago

@onovotny I'm going to go ahead with using the Xamarin Forms Backgrounding technique to handle long running test tasks.

ToddThomson commented 6 years ago

@onovotny Why doesn't UWP get a package reference to Xamarin.Forms in csproj?

<PackageReference Condition="'$(IsXamForms)' == 'true'" Include="Xamarin.Forms" Version="3.0.0.482510" />
clairernovotny commented 6 years ago

Because UWP has its own UWP XAML Implementation due to Xam Forms not working well with .NET Native at the time. (it may be better now).