Skip to content

Commit 3769f82

Browse files
committed
Refactor
1 parent 8ea4950 commit 3769f82

5 files changed

Lines changed: 284 additions & 211 deletions

File tree

samples/public/BlankAndroid/BlankAndroid.csproj

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
1111
<TrimMode>partial</TrimMode>
1212

13+
<!-- Mark as a test project - this enables all testing infrastructure -->
14+
<IsTestProject>true</IsTestProject>
15+
1316
<!-- Enable Microsoft Testing Platform -->
1417
<IsTestingPlatformApplication>true</IsTestingPlatformApplication>
1518
<EnableMSTestRunner>true</EnableMSTestRunner>
@@ -19,11 +22,11 @@
1922
<UseMSTestEngine>true</UseMSTestEngine>
2023
<UseMSTestAdapter>false</UseMSTestAdapter>
2124

22-
<!-- Device test project -->
25+
<!-- Device test project - uses MSBuild infrastructure instead of VSTest -->
26+
<!-- This is set automatically by Microsoft.Testing.Platform.MSBuild.DeviceTesting.targets -->
27+
<!-- but we set it here for compatibility with older package versions -->
2328
<_IsDeviceTestProject>true</_IsDeviceTestProject>
24-
25-
<!-- Disable fast deployment - instrumentation requires all assemblies in APK -->
26-
<!-- <EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk> -->
29+
<UseMSBuildTestInfrastructure>true</UseMSBuildTestInfrastructure>
2730
</PropertyGroup>
2831

2932
<ItemGroup>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project>
2+
<!-- Import parent props -->
3+
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
4+
5+
<!--
6+
Set device test project properties early (before NuGet package targets).
7+
This prevents the VSTest error in Microsoft.Testing.Platform.MSBuild from being raised.
8+
-->
9+
<PropertyGroup Condition="'$(TargetFramework)' != '' AND ($(TargetFramework.Contains('android')) OR $(TargetFramework.Contains('ios')))">
10+
<_IsDeviceTestProject>true</_IsDeviceTestProject>
11+
<UseMSBuildTestInfrastructure>true</UseMSBuildTestInfrastructure>
12+
<!-- Opt-in to new dotnet test experience to bypass VSTest error -->
13+
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
14+
</PropertyGroup>
15+
</Project>
Lines changed: 22 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,29 @@
11
<Project>
2-
<PropertyGroup>
3-
<_IsDeviceTestProject Condition="$(TargetFramework.Contains('android')) OR $(TargetFramework.Contains('ios'))">true</_IsDeviceTestProject>
4-
<UseMSBuildTestInfrastructure Condition="'$(_IsDeviceTestProject)' == 'true'">true</UseMSBuildTestInfrastructure>
5-
<DeviceId Condition="'$(DeviceId)' == ''">$(DEVICE_ID)</DeviceId>
6-
<!--
7-
DotnetDevicePath: Path to the dotnet executable with device support (.NET 11+)
8-
Priority: 1) Explicit property, 2) Environment variable, 3) DOTNET_HOST_PATH (same SDK running this build), 4) system dotnet
9-
-->
10-
<DotnetDevicePath Condition="'$(DotnetDevicePath)' == ''">$(DOTNET_DEVICE_PATH)</DotnetDevicePath>
11-
<DotnetDevicePath Condition="'$(DotnetDevicePath)' == ''">$(DOTNET_HOST_PATH)</DotnetDevicePath>
12-
<DotnetDevicePath Condition="'$(DotnetDevicePath)' == ''">dotnet</DotnetDevicePath>
13-
<!--
14-
UseInstrumentation: When true, uses Android Instrumentation to run tests via 'adb instrument'
15-
This allows tests to run in a controlled environment and properly wait for completion.
16-
When false (default), uses 'dotnet run' which launches the MainActivity.
17-
-->
18-
<UseInstrumentation Condition="'$(UseInstrumentation)' == ''">false</UseInstrumentation>
19-
<!--
20-
AndroidInstrumentationName: The full name of the Instrumentation class as registered.
21-
Must match the Name attribute in [Instrumentation(Name = "...")] on your TestInstrumentation class.
22-
Example: blankandroid.TestInstrumentation
23-
-->
24-
<AndroidInstrumentationName Condition="'$(AndroidInstrumentationName)' == ''">blankandroid.TestInstrumentation</AndroidInstrumentationName>
25-
</PropertyGroup>
26-
27-
<Target Name="_MTPBeforeVSTest" BeforeTargets="VSTest" Condition="'$(_IsDeviceTestProject)' == 'true'">
28-
<Message Text="Device project detected, skipping MTP VSTest error check" Importance="low" />
29-
</Target>
30-
31-
<Target Name="VSTest" Condition="'$(_IsDeviceTestProject)' == 'true'">
32-
<Message Text="" Importance="high" />
33-
<Message Text="╔══════════════════════════════════════════════════════════════╗" Importance="high" />
34-
<Message Text="║ DEVICE TESTING (Microsoft.Testing.Platform) ║" Importance="high" />
35-
<Message Text="╠══════════════════════════════════════════════════════════════╣" Importance="high" />
36-
<Message Text="║ Project: $(MSBuildProjectName)" Importance="high" />
37-
<Message Text="║ Framework: $(TargetFramework)" Importance="high" />
38-
<Message Text="║ Device: $(DeviceId)" Importance="high" Condition="'$(DeviceId)' != ''" />
39-
<Message Text="║ Dotnet: $(DotnetDevicePath)" Importance="high" />
40-
<Message Text="║ Mode: $(UseInstrumentation.Replace('true','Instrumentation (adb)').Replace('false','Activity (dotnet run)'))" Importance="high" />
41-
<Message Text="╚══════════════════════════════════════════════════════════════╝" Importance="high" />
42-
<Message Text="" Importance="high" />
2+
<!--
3+
This Directory.Build.targets file imports the Android device testing targets.
434
44-
<!-- Choose which mode to run tests -->
45-
<CallTarget Targets="_RunTestsOnDeviceViaDotnetRun" Condition="'$(UseInstrumentation)' != 'true'" />
46-
<CallTarget Targets="_RunTestsOnDeviceViaInstrumentation" Condition="'$(UseInstrumentation)' == 'true'" />
47-
<CallTarget Targets="_CollectDeviceTestResults" />
48-
</Target>
49-
50-
<!--
51-
Mode 1: Run tests via 'dotnet run' (default)
52-
Uses MainActivity to run tests. Simple but app may not signal completion properly.
53-
-->
54-
<Target Name="_RunTestsOnDeviceViaDotnetRun" Condition="$(TargetFramework.Contains('android'))">
55-
<PropertyGroup>
56-
<_DeviceArg Condition="'$(DeviceId)' != ''">--device $(DeviceId)</_DeviceArg>
57-
<_LocalTestResultsPath>$(OutputPath)TestResults</_LocalTestResultsPath>
58-
<_AdbDevice Condition="'$(DeviceId)' != ''">-s $(DeviceId)</_AdbDevice>
59-
</PropertyGroup>
60-
61-
<!-- Clear logcat before running tests -->
62-
<Exec Command="adb $(_AdbDevice) logcat -c"
63-
WorkingDirectory="$(MSBuildProjectDirectory)"
64-
IgnoreExitCode="true" />
65-
66-
<Message Text="" Importance="high" />
67-
<Message Text="Running tests via: dotnet run --project $(MSBuildProjectFullPath) -f $(TargetFramework) $(_DeviceArg)" Importance="high" />
68-
<Message Text="" Importance="high" />
5+
In production, these targets would be imported automatically from the dotnet/android SDK
6+
when a project targets net*-android and has IsTestProject=true.
697
70-
<!--
71-
Use 'dotnet run' with device argument which:
72-
1. Builds the project
73-
2. Deploys to the device/emulator
74-
3. Runs the app and streams output
75-
4. Waits for app to exit
76-
-->
77-
<Exec Command="&quot;$(DotnetDevicePath)&quot; run --project &quot;$(MSBuildProjectFullPath)&quot; -f $(TargetFramework) $(_DeviceArg)"
78-
WorkingDirectory="$(MSBuildProjectDirectory)"
79-
IgnoreExitCode="true"
80-
ConsoleToMSBuild="true">
81-
<Output TaskParameter="ExitCode" PropertyName="_DotnetRunExitCode" />
82-
<Output TaskParameter="ConsoleOutput" PropertyName="_DotnetRunOutput" />
83-
</Exec>
84-
85-
<!-- Show output -->
86-
<Message Text="" Importance="high" />
87-
<Message Text="$(_DotnetRunOutput)" Importance="high" />
88-
89-
<Message Text="" Importance="high" />
90-
<Message Text="══════════════════════════════════════════════════════════════" Importance="high" />
91-
<Message Text="✓ dotnet run completed with exit code: $(_DotnetRunExitCode)" Importance="high" Condition="'$(_DotnetRunExitCode)' == '0'" />
92-
<Warning Text="⚠ dotnet run completed with exit code: $(_DotnetRunExitCode)" Condition="'$(_DotnetRunExitCode)' != '0'" />
93-
</Target>
94-
8+
For development/testing, we import them from the local file.
9+
-->
10+
11+
<!-- Set device test project flag early to skip VSTest error in NuGet package -->
12+
<PropertyGroup Condition="'$(TargetFramework)' != '' AND $(TargetFramework.Contains('android'))">
13+
<_IsDeviceTestProject>true</_IsDeviceTestProject>
14+
<UseMSBuildTestInfrastructure>true</UseMSBuildTestInfrastructure>
15+
</PropertyGroup>
16+
9517
<!--
96-
Mode 2: Run tests via Android Instrumentation (adb instrument)
97-
Uses TestInstrumentation class. Properly waits for test completion and returns exit code.
98-
Enable with: -p:UseInstrumentation=true
18+
Override _MTPBeforeVSTest to prevent error for device projects.
19+
The installed NuGet package (2.0.2) doesn't have device testing support yet,
20+
so we need to override its error-throwing target.
9921
-->
100-
<Target Name="_RunTestsOnDeviceViaInstrumentation" Condition="$(TargetFramework.Contains('android'))">
101-
<PropertyGroup>
102-
<_AdbDevice Condition="'$(DeviceId)' != ''">-s $(DeviceId)</_AdbDevice>
103-
<_LocalTestResultsPath>$(OutputPath)TestResults</_LocalTestResultsPath>
104-
<!--
105-
AndroidInstrumentationName: The full name of the Instrumentation class as registered in AndroidManifest.xml
106-
Must match the Name attribute in [Instrumentation(Name = "...")]
107-
Default: blankandroid.TestInstrumentation - override in project if using different name
108-
-->
109-
<_InstrumentationClass>$(ApplicationId)/$(AndroidInstrumentationName)</_InstrumentationClass>
110-
</PropertyGroup>
111-
112-
<!-- Clear logcat before running tests -->
113-
<Exec Command="adb $(_AdbDevice) logcat -c"
114-
WorkingDirectory="$(MSBuildProjectDirectory)"
115-
IgnoreExitCode="true" />
116-
117-
<Message Text="" Importance="high" />
118-
<Message Text="Building and installing app..." Importance="high" />
119-
120-
<!-- Build and install the app using dotnet build -t:Install -->
121-
<Exec Command="&quot;$(DotnetDevicePath)&quot; build &quot;$(MSBuildProjectFullPath)&quot; -f $(TargetFramework) -t:Install -p:AdbTarget=&quot;$(_AdbDevice)&quot;"
122-
WorkingDirectory="$(MSBuildProjectDirectory)"
123-
IgnoreExitCode="false">
124-
<Output TaskParameter="ExitCode" PropertyName="_InstallExitCode" />
125-
</Exec>
126-
127-
<Message Text="" Importance="high" />
128-
<Message Text="Running tests via: adb $(_AdbDevice) shell am instrument -w $(_InstrumentationClass)" Importance="high" />
129-
<Message Text="" Importance="high" />
130-
131-
<!--
132-
Run tests via instrumentation which:
133-
1. Starts the TestInstrumentation class
134-
2. Waits for completion (-w flag)
135-
3. Returns proper exit code based on test results
136-
-->
137-
<Exec Command="adb $(_AdbDevice) shell am instrument -w $(_InstrumentationClass)"
138-
WorkingDirectory="$(MSBuildProjectDirectory)"
139-
IgnoreExitCode="true"
140-
ConsoleToMSBuild="true">
141-
<Output TaskParameter="ExitCode" PropertyName="_InstrumentExitCode" />
142-
<Output TaskParameter="ConsoleOutput" PropertyName="_InstrumentOutput" />
143-
</Exec>
144-
145-
<!-- Show output -->
146-
<Message Text="" Importance="high" />
147-
<Message Text="$(_InstrumentOutput)" Importance="high" />
148-
149-
<Message Text="" Importance="high" />
150-
<Message Text="══════════════════════════════════════════════════════════════" Importance="high" />
151-
<Message Text="✓ Instrumentation completed with exit code: $(_InstrumentExitCode)" Importance="high" Condition="'$(_InstrumentExitCode)' == '0'" />
152-
<Warning Text="⚠ Instrumentation completed with exit code: $(_InstrumentExitCode)" Condition="'$(_InstrumentExitCode)' != '0'" />
153-
</Target>
154-
155-
<Target Name="_CollectDeviceTestResults">
156-
<PropertyGroup>
157-
<_AdbDevice Condition="'$(DeviceId)' != ''">-s $(DeviceId)</_AdbDevice>
158-
<_DeviceTestResultsPath>files/TestResults</_DeviceTestResultsPath>
159-
<_LocalTestResultsPath>$(OutputPath)TestResults</_LocalTestResultsPath>
160-
<_LogcatFileName>$(MSBuildProjectName)_logcat.txt</_LogcatFileName>
161-
</PropertyGroup>
162-
163-
<!-- Create local TestResults directory -->
164-
<MakeDir Directories="$(_LocalTestResultsPath)" />
165-
166-
<Message Text="" Importance="high" />
167-
<Message Text="Collecting test results from device..." Importance="high" />
168-
169-
<!-- Capture full logcat to file for debugging -->
170-
<Exec Command="adb $(_AdbDevice) logcat -d > &quot;$(_LocalTestResultsPath)/$(_LogcatFileName)&quot;"
171-
WorkingDirectory="$(MSBuildProjectDirectory)"
172-
IgnoreExitCode="true"
173-
IgnoreStandardErrorWarningFormat="true" />
174-
175-
<Message Text="Logcat saved: $(_LocalTestResultsPath)/$(_LogcatFileName)" Importance="high" />
176-
177-
<!-- Get the most recent TRX file name -->
178-
<Exec Command="adb $(_AdbDevice) shell &quot;run-as $(ApplicationId) ls -t $(_DeviceTestResultsPath)/ 2>/dev/null | head -1&quot; | tr -d '\r'"
179-
WorkingDirectory="$(MSBuildProjectDirectory)"
180-
IgnoreExitCode="true"
181-
IgnoreStandardErrorWarningFormat="true"
182-
ConsoleToMSBuild="true">
183-
<Output TaskParameter="ConsoleOutput" PropertyName="_LatestTrxFileName" />
184-
</Exec>
185-
186-
<!-- Pull the latest TRX file using run-as + cat -->
187-
<Exec Command="adb $(_AdbDevice) shell &quot;run-as $(ApplicationId) cat $(_DeviceTestResultsPath)/$(_LatestTrxFileName)&quot; > &quot;$(_LocalTestResultsPath)/$(MSBuildProjectName).trx&quot;"
188-
WorkingDirectory="$(MSBuildProjectDirectory)"
189-
IgnoreExitCode="true"
190-
IgnoreStandardErrorWarningFormat="true"
191-
Condition="'$(_LatestTrxFileName)' != '' AND $(_LatestTrxFileName.EndsWith('.trx'))" />
192-
193-
<!-- Show result -->
194-
<Message Text="Test results: $(_LocalTestResultsPath)/$(MSBuildProjectName).trx" Importance="high" Condition="'$(_LatestTrxFileName)' != '' AND $(_LatestTrxFileName.EndsWith('.trx'))" />
22+
<Target Name="_MTPBeforeVSTest" BeforeTargets="VSTest" Condition="'$(_IsDeviceTestProject)' == 'true'">
23+
<Message Text="Device test project detected - skipping VSTest error check" Importance="high" />
19524
</Target>
25+
26+
<!-- Import Android device testing targets (will live in dotnet/android SDK) -->
27+
<Import Project="$(MSBuildThisFileDirectory)Sdk.DeviceTesting.Android.targets"
28+
Condition="'$(TargetFramework)' != '' AND $(TargetFramework.Contains('android'))" />
19629
</Project>

samples/public/BlankAndroid/MainActivity.cs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@ private async Task RunTestsAsync()
3232

3333
Directory.CreateDirectory(testResultsDir);
3434

35-
Log.Info(TAG, $"╔══════════════════════════════════════════════════════════════╗");
36-
Log.Info(TAG, $"║ DEVICE TEST EXECUTION STARTING ║");
37-
Log.Info(TAG, $"╠══════════════════════════════════════════════════════════════╣");
38-
Log.Info(TAG, $"║ Results Directory: {testResultsDir}");
39-
Log.Info(TAG, $"╚══════════════════════════════════════════════════════════════╝");
35+
Log.Info(TAG, $"Test results directory: {testResultsDir}");
4036

4137
// Configure test arguments
4238
var args = new[]
@@ -45,21 +41,12 @@ private async Task RunTestsAsync()
4541
"--report-trx"
4642
};
4743

48-
Log.Info(TAG, "Calling MicrosoftTestingPlatformEntryPoint.Main...");
44+
Log.Info(TAG, "Starting test execution...");
4945

5046
// Run the tests via the generated entry point
5147
exitCode = await MicrosoftTestingPlatformEntryPoint.Main(args);
5248

53-
Log.Info(TAG, $"╔══════════════════════════════════════════════════════════════╗");
54-
if (exitCode == 0)
55-
{
56-
Log.Info(TAG, $"║ ✓ TESTS PASSED (exit code: {exitCode}) ║");
57-
}
58-
else
59-
{
60-
Log.Error(TAG, $"║ ✗ TESTS FAILED (exit code: {exitCode}) ║");
61-
}
62-
Log.Info(TAG, $"╚══════════════════════════════════════════════════════════════╝");
49+
Log.Info(TAG, $"Tests completed with exit code: {exitCode}");
6350
}
6451
catch (Exception ex)
6552
{
@@ -68,10 +55,9 @@ private async Task RunTestsAsync()
6855
}
6956
finally
7057
{
71-
Log.Info(TAG, $"Test execution complete. Finishing activity with exit code: {exitCode}");
58+
Log.Info(TAG, $"Finishing activity with exit code: {exitCode}");
7259

7360
// Finish the activity and exit the process
74-
// This signals to 'dotnet run' that the app has completed
7561
RunOnUiThread(() =>
7662
{
7763
FinishAffinity();

0 commit comments

Comments
 (0)