diff --git a/tests/MSTest.Android.Tests/Libraries/JavaInterop/InteropTests.cs b/tests/MSTest.Android.Tests/Libraries/JavaInterop/InteropTests.cs
new file mode 100644
index 00000000000..f8fff1acfe4
--- /dev/null
+++ b/tests/MSTest.Android.Tests/Libraries/JavaInterop/InteropTests.cs
@@ -0,0 +1,50 @@
+using AndroidMSTestProof.TestLibrary;
+using Java.Interop;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+[assembly: DoNotParallelize]
+
+namespace AndroidMSTestProof.JavaInterop;
+
+[TestClass]
+public class InteropTests : LifecycleBase
+{
+ [TestMethod]
+ [TestCategory ("proof")]
+ [TestCategory ("jni")]
+ public void ReferencedJNI ()
+ {
+ AssertInitialized ();
+ using var value = new Java.Lang.String ("referenced JNI");
+ Assert.AreEqual ("referenced JNI", value.ToString ());
+ Assert.AreNotEqual (IntPtr.Zero, JniEnvironment.EnvironmentPointer);
+ Context.WriteLine ("[D ASSEMBLY] " + typeof (InteropTests).Assembly.GetName ().Name);
+ }
+
+#pragma warning disable MSTEST0087 // Matching display names deliberately test distinct JNI row identities.
+ [TestMethod]
+ [TestCategory ("proof")]
+ [TestCategory ("jni")]
+ [DataRow ("first", DisplayName = "same JNI display")]
+ [DataRow ("second", DisplayName = "same JNI display")]
+ public void StringRoundtrip (string text)
+ {
+ AssertInitialized ();
+ var reference = JniEnvironment.Strings.NewString (text);
+ try {
+ Assert.IsTrue (reference.IsValid);
+ Assert.AreEqual (text, JniEnvironment.Strings.ToString (reference));
+ } finally {
+ JniObjectReference.Dispose (ref reference);
+ }
+ }
+#pragma warning restore MSTEST0087
+
+ [TestMethod]
+ [TestCategory ("diagnostic")]
+ public void GeneratedInteropFailure ()
+ {
+ AssertInitialized ();
+ Assert.Fail ("intentional referenced-JavaInterop generated invocation failure");
+ }
+}
diff --git a/tests/MSTest.Android.Tests/Libraries/JavaInterop/MSTest.Android.JavaInterop.Tests.csproj b/tests/MSTest.Android.Tests/Libraries/JavaInterop/MSTest.Android.JavaInterop.Tests.csproj
new file mode 100644
index 00000000000..a688dfdb38a
--- /dev/null
+++ b/tests/MSTest.Android.Tests/Libraries/JavaInterop/MSTest.Android.JavaInterop.Tests.csproj
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/MSTest.Android.Tests/Libraries/TestLibrary/LifecycleTests.cs b/tests/MSTest.Android.Tests/Libraries/TestLibrary/LifecycleTests.cs
new file mode 100644
index 00000000000..a1d69acafe9
--- /dev/null
+++ b/tests/MSTest.Android.Tests/Libraries/TestLibrary/LifecycleTests.cs
@@ -0,0 +1,82 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+[assembly: DoNotParallelize]
+
+namespace AndroidMSTestProof.TestLibrary;
+
+public abstract class LifecycleBase
+{
+ int initialized;
+ int cleaned;
+
+ public TestContext? TestContext { get; set; }
+
+ protected TestContext Context => TestContext ?? throw new InvalidOperationException ("MSTest did not assign the inherited context.");
+
+ [TestInitialize]
+ public void Initialize ()
+ {
+ Assert.AreEqual (1, ++initialized);
+ Assert.AreEqual (0, cleaned);
+ using var value = new Java.Lang.String ("initialize");
+ Assert.AreEqual ("initialize", value.ToString ());
+ Context.WriteLine ($"[D INITIALIZE] {GetType ().FullName} {Context.TestName} calls={initialized}");
+ }
+
+ [TestCleanup]
+ public void Cleanup ()
+ {
+ Assert.AreEqual (1, initialized);
+ Assert.AreEqual (1, ++cleaned);
+ using var value = new Java.Lang.String ("cleanup");
+ Assert.AreEqual ("cleanup", value.ToString ());
+ Context.WriteLine ($"[D CLEANUP] {GetType ().FullName} {Context.TestName} calls={cleaned} outcome={Context.CurrentTestOutcome}");
+ }
+
+ protected void AssertInitialized ()
+ {
+ Assert.AreEqual (1, initialized);
+ Assert.AreEqual (0, cleaned);
+ }
+}
+
+[TestClass]
+public class LibraryTests : LifecycleBase
+{
+ [TestMethod]
+ [TestCategory ("proof")]
+ [TestCategory ("library")]
+ public void ReferencedLibrary ()
+ {
+ AssertInitialized ();
+ Assert.AreEqual (typeof (LibraryTests).Assembly, GetType ().Assembly);
+ Context.WriteLine ("[D ASSEMBLY] " + typeof (LibraryTests).Assembly.GetName ().Name);
+ }
+
+ [TestMethod]
+ [TestCategory ("proof")]
+ [TestCategory ("library")]
+ public async Task AsyncLibrary ()
+ {
+ AssertInitialized ();
+ await Task.Delay (1);
+ AssertInitialized ();
+ }
+
+ [TestMethod]
+ [TestCategory ("proof")]
+ [TestCategory ("library")]
+ public void InconclusiveLibrary ()
+ {
+ AssertInitialized ();
+ Assert.Inconclusive ("intentional D inconclusive; inherited cleanup must execute");
+ }
+
+ [TestMethod]
+ [TestCategory ("diagnostic")]
+ public void GeneratedLibraryFailure ()
+ {
+ AssertInitialized ();
+ Assert.Fail ("intentional referenced-library generated invocation failure");
+ }
+}
diff --git a/tests/MSTest.Android.Tests/Libraries/TestLibrary/MSTest.Android.TestLibrary.Tests.csproj b/tests/MSTest.Android.Tests/Libraries/TestLibrary/MSTest.Android.TestLibrary.Tests.csproj
new file mode 100644
index 00000000000..1cc587947b5
--- /dev/null
+++ b/tests/MSTest.Android.Tests/Libraries/TestLibrary/MSTest.Android.TestLibrary.Tests.csproj
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/MSTest.Android.Tests/MSTest.Android.Tests.csproj b/tests/MSTest.Android.Tests/MSTest.Android.Tests.csproj
new file mode 100644
index 00000000000..3bc7c7ea5e6
--- /dev/null
+++ b/tests/MSTest.Android.Tests/MSTest.Android.Tests.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net.dot.android.mstestproof
+ net.dot.android.mstestproof.Instrumentation
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/MSTest.Android.Tests/ProofTests.cs b/tests/MSTest.Android.Tests/ProofTests.cs
new file mode 100644
index 00000000000..dd1f5bb7fb7
--- /dev/null
+++ b/tests/MSTest.Android.Tests/ProofTests.cs
@@ -0,0 +1,106 @@
+using System.Reflection;
+using AndroidMSTestProof.TestLibrary;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+[assembly: DoNotParallelize]
+
+namespace AndroidMSTestProof;
+
+[TestClass]
+public class ProofTests : LifecycleBase
+{
+ [TestMethod]
+ [TestCategory ("proof")]
+ public void AndroidBinding ()
+ {
+ AssertInitialized ();
+ Assert.IsTrue (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N);
+ Assert.AreEqual ("Mono.Android", typeof (Java.Lang.String).Assembly.GetName ().Name);
+ }
+
+ [TestMethod]
+ [TestCategory ("proof")]
+ public async Task AsyncTask ()
+ {
+ AssertInitialized ();
+ await Task.Delay (1);
+ AssertInitialized ();
+ using var value = new Java.Lang.String ("async JNI");
+ Assert.AreEqual ("async JNI", value.ToString ());
+ }
+
+ [TestMethod]
+ [TestCategory ("proof")]
+ public async ValueTask AsyncValueTask ()
+ {
+ AssertInitialized ();
+ await Task.Delay (1);
+ AssertInitialized ();
+ }
+
+#pragma warning disable MSTEST0042, MSTEST0087 // Identical arguments and display names deliberately test row identity.
+ [TestMethod]
+ [TestCategory ("proof")]
+ [DataRow (0, DisplayName = "same data display")]
+ [DataRow (0, DisplayName = "same data display")]
+ [DataRow (1, DisplayName = "same data display")]
+ public void DataRows (int row)
+ {
+ AssertInitialized ();
+ Assert.IsTrue (row is 0 or 1);
+ Context.WriteLine ($"[D ROW] DataRows value={row}");
+ }
+#pragma warning restore MSTEST0042, MSTEST0087
+
+ public static IEnumerable