Xamarin (Android) Unit Tests in Visual Studio 2017

Xamarin (Android) Unit Tests in Visual Studio 2017

There are three basic levels of testing:

The classic unit testing of pure .Net/Mono code via xUnit|NUnit

  • Nothing new here, this is the same testing that .Net programmers have been doing all long and has nothing to do with the Xamarin platform frameworks

Note: These tests are totally independent of Xamarin.Android|iOS|Mac

On platform testing (including platform features)

Note: There are multiple on device testing wrappers for NUnit, XUnit, etc... Xamarin includes a NUnitLite version that runs on Android and iOS and that provide a device specific UI to run those tests. Xamarin has templates that create a Unit Test App project for Android or iOS.

Note: These tests can include platform dependent features (Networking, Bluetooth, GPS, SMS, etc... but no GUI related tests) and can also reference Nunit [Test]s written in PCL-based assemblies or platform-specific libraries.

  • Xamarin.iOS Unit Testing
  • Xamarin.Mac Unit Testing via GUIUnit
  • Xamarin.Android Setup and Automating
Alternatives to NUnitLite:
  • xUnit.net Runners for Devices
  • NUnit test runners for Xamarin and mobile devices

UI Testing

A Casabash/Appium/... driven tests of the UI elements in your application and their reaction to input (touch) events.

  • Test Cloud/Mobile Center and/or other local, public or private mobile test clouds

  • Xamarin Test Cloud

Xamarin Android UnitTest and Instrumentation Test (not Forms)

Thanks to @jgoldberger-MSFT and @SushiHangover for their comments.

In the end I had two options to achieve my goal:

  • xUnit Framework.
  • Xamarin Android Instrumented Tests (NUnitLite).

Setting up XUnit for Xamarin Android


You can run tests on the device with by using xUnit Framework and xUnit.Runner.Devices. However, the test package (all your classes of testing and configuration) must be attached to the current Xamarin Android project in the solution, so that the reference of the same project (including classes, resources, and the context of the application) can be used satisfactorily. Otherwise, this will generate a lot of endless errors referring to Android resources, because you can not put two applications together.

Once installed both Frameworks mentioned above, just make the configuration of your launch activity as follows:

  • At top of your MainLauncher Activity class, define a Preprocessor Directive: This will allow you to run the application for tests or with normal flow. Note that it has the Debug directive, which will allow you to only execute the condition if the application will deploy in debug.

.

 //#define TEST // Uncomment this to start UnitTestig

. . .

[ /* Your ActivityAttributes */ ]
public class YourLauncherActivity : Activity {

protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
#if (DEBUG && TEST)
// Your TestConfiguration.cs Activity
Intent iTestConfiguration = new Intent(this, typeof(TestConfiguration));
StartActivity(iTestConfiguration);
#endif
#if !TEST
// Run your normal Activity here, like Login, etc...
#endif
}
}

...

Your test setup activity should look something like this: TestConfiguration.cs

    [Activity(Label = "TestConfiguration")]
public class TestConfiguration : Xunit.Runners.UI.RunnerActivity
{
//public static Context Context { get; set; }

protected override void OnCreate(Bundle bundle)
{
// tests can be inside the main assembly
AddTestAssembly(Assembly.GetExecutingAssembly());
AddExecutionAssembly(typeof(ExtensibilityPointFactory).Assembly);
// or in any reference assemblies
//this.AutoStart = true;
base.OnCreate(bundle);
//Context = this;
}
}

Then define your tests within the project, using xUnit Framework, for example: MyTests.cs

public class MyTests
{

public MyTests()
{
// Before each test
}

[Fact]
public void FailingTest()
{
Assert.True(false);
}
}

Now you can run the tests on the xUnit Runner for Devices Activity that was created.

Setting up Xamarin Android Instrumentation


Now, if you want to run instrumentation test in a Xamarin Android project, you should do the following:

First of all, execute the following tutorial step by step:

  • Instrumentation test in a Xamarin Android project

Once complete, add a static reference to your TestSuiteInstrumentation in the configuration class of your test, for example: TestInstrumentation.cs

. . .
public static TestSuiteInstrumentation CurrentInstrumentation { get; set; }

public TestInstrumentation(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer)
{
CurrentInstrumentation = this;
}
. . .

Now if you want to configure your tests so that you want to run an Activity implicitly and use its views, properties, etc ... You can do the following: Example for my Login.cs Activity

    [TestFixture]
public class LoginTests
{
private TestSuiteInstrumentation instrument = TestInstrumentation.CurrentInstrumentation;
private Activity CurrentActivity;

[SetUp]
public void SetUp()
{
Instrumentation.ActivityMonitor monitor = instrument.AddMonitor($"{instrument.TargetContext.PackageName}." + nameof(Login), null, false);

Intent intent = new Intent();
intent.AddFlags(ActivityFlags.NewTask);
intent.SetClassName(instrument.TargetContext, $"{instrument.TargetContext.PackageName}." + nameof(Login));

Task.Run(() => instrument.StartActivitySync(intent)).GetAwaiter();

Activity currentActivity = instrument.WaitForMonitor(monitor);

}

[Test]
public void LoginTest()
{
// Verify your activity is not null
Assert.NotNull(CurrentActivity);

// Convert CurrentActivity to your Activity
Login login = CurrentActivity as Login;

// Verify your views are not null, finding views in your Activity
Assert.NotNull(login);
Assert.NotNull(login.FindViewById<EditText>(Resource.Id.etLoginUsername));
Assert.NotNull(login.FindViewById<EditText>(Resource.Id.etLoginPassword));

instrument.RunOnMainSync(() => {

// Here you can run your UI methods or properties for Views, example
login.FindViewById<EditText>(Resource.Id.etLoginUsername).Text = "hello";
login.FindViewById<EditText>(Resource.Id.etLoginPassword).Text = "world";
});

// Here will be your assertions
}
}

Now run your test with ADB. Following this steps:

  • Deploy your application in debug or release mode. Then stop it.
  • Locate your instrumentation tests, use the following command:

    adb shell pm list instrumentation

  • Copy the complete name of the test you want to execute and execute the following command:

    adb shell am instrument -w /*paste the full name of your instrumentation test*/

IMPORTANT: Your activity needs to have a defined name in the ActivityAttribute to prevent the classes.dex file from finding your class. For example, if my PackageName is com.yourpackage.android and my Activity class is Login.cs at your ActivityAttributes add:

[Activity( ... , Name ="com.yourpackage.android.Login", ...)]

Xamarin Android Nunit tests discoverable in test explorer, but aren't discovered when running tests. (VS2017)

The NUnit Test Adapter does not support running Android tests in the Visual Studio Test Runner. (I think this is a limitation of the VS test runner, but I'm not 100% sure on that!)

You should instead launch NUnit.Tests.Droid1 as an Android app, either in a simulator or on a device. The app will be a GUI test runner, which will allow you to run your tests.

It'll look something a little like this:

Sample Image

One other thing - you app should be referencing the same version of NUnit as nunit.xamarin - so you really want to be pulling in NUnit 3.6.1 rather than NUnit 3.11. That's planned to change in future!

Xamarin - Unit Test App (android) - defining usage

I want to quote JohnathanPryor from Xamarin to answer your question:

Don't add Application projects to Application projects; things
generally won't work as you expect.

Instead...

Because adding Application projects as project references to
Application projects is (still!) not advised (at least until using
Wear project support), this was never a good way to unit test your
code.

Thus, what you should instead do is place any code you want to have
used by a Unit Test Project be within an Android Library (or PCL)
project. This will ensure that the type you're testing can use Android
Resources "normally", have things generally work as expected and
desired, and your code will be usable by both the Unit Test project
and the Application project you really care about.

Again, quoting that thread, one of the possible solutions is

MyProj (Solution)

  • MyProj (PCL)
  • MyProj.Android (default Xamarin project)
  • MyProj.Android.Shared (Android Class Library)
  • MyProj.Android.Test> (Android Unit Test App)
  • MyProj.iOS (default Xamarin project)

Where MyProj.Android contains almost nothing and MyProj.Android.Shared
contains everything (Activities/Bundles et all) so that they can be
referenced in the Android unit tests

or

using a Shared Project

Tests showing twice in Unit Tests pad - Visual Studio 2017 for Mac

The problem was caused by my Tests class inheriting from a BaseTestFixture class and both of them having the

[TestFixture(Platform.Android)]
[TestFixture(Platform.iOS)]

attributes.

Removing these attributes from my derived class solved the problem.

Mono for Android - Unit Testing with Visual Studio

I ended up using MonoDroid-UnitTest. I find it's the only Xamarin Android unit test framework I've seen that's being actively maintained



Related Topics



Leave a reply



Submit