You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add some notes on testing trimming
* Fix slashes in links
Co-authored-by: Eric Erhardt <[email protected]>
---------
Co-authored-by: Eric Erhardt <[email protected]>
We have infrastructure for writing tests to validate trimming behavior.
55
+
The two most common tasks are confirming that functionality still works after trimming and confirming that a particular type or member was not preserved.
56
+
57
+
### Infrastructure
58
+
59
+
Because trimming is only performed during publish, the tests can't be normal xunit tests.
60
+
Instead, we have a system that wraps individual source files in appropriately configured projects and publishes them as standalone executables.
61
+
These executables are then run and the test outcome is based on the exit code.
62
+
The tests are powered by [trimmingTests.targets](../eng/testing/linker/trimmingTests.targets), which is based on corresponding functionality in https://github.com/dotnet/runtime.
63
+
64
+
### Adding a new test project
65
+
66
+
Adding a new test project is very simple - just call it *.TrimmingTests.proj and give it a body like
67
+
```xml
68
+
<ProjectSdk="Microsoft.NET.Sdk">
69
+
<ItemGroup>
70
+
<TestConsoleAppSourceFilesInclude="MyTest.cs">
71
+
</ItemGroup>
72
+
</Project>
73
+
```
74
+
75
+
Unfortunately, there's no good way to specify which aspnetcore projects the tests depend upon so, to avoid dependency ordering problems, it's easiest to specify that they should be built after the main build.
76
+
Do this by adding an entry to [RequiresDelayedBuildProjects.props](../eng/RequiresDelayedBuildProjects.props).
77
+
78
+
### Adding a new test
79
+
80
+
A test is just a C# file with a main method (or top-level statements, if you prefer).
81
+
Write a program that either should keep working after trimming or that validates a particular type/member has been trimmed (e.g. using `Type.GetType`).
82
+
If things behave as expected exit with code `100` (a magic number intended to prevent accidental passes).
83
+
Any other result - a different exit code or a crash - will count as a failure.
84
+
85
+
Now that you have a test program, add a `TestConsoleAppSourceFiles` item to the corresponding test project.
86
+
87
+
If you have additional files, typically because you want to share code between tests, you can use `AdditionalSourceFiles`.
88
+
If you want to en/disable a particular feature switch, you can use `EnabledFeatureSwitches`/`DisabledFeatureSwitches`.
89
+
90
+
### Running tests
91
+
92
+
To run the tests locally, build the projects it depends on (it's usually easiest to just build the whole repo) and then run
93
+
```
94
+
.dotnet\dotnet.exe test path\to\project\folder\
95
+
```
96
+
97
+
Alternatively, you can use `Activate.ps1` to ensure you're using the right dotnet binary.
98
+
99
+
### Native AOT
100
+
101
+
Native AOT testing is substantially the same - just name your project *.NativeAotTests.proj, rather than *.TrimmingTests.proj.
102
+
103
+
### Tips
104
+
105
+
- It's easier to author your test as a standalone Native AOT app and then copy the final code into the test (don't forget to add the copyright header).
106
+
The two main advantages are that building is much faster and you get console output that you can use to help debug your test.
107
+
- If you are using AdditionalSourceFiles and you need to make a change to one of the additional files, you will also need to update the test file itself - just editing the additional file _won't trigger a rebuild_ on the next run.
108
+
-`Type.GetType` is known to the trimmer, so you'll have to (a) make it impossible to statically determine what argument you're passing (so that it isn't preserved) and (b) suppress the resulting warning: `[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057:UnrecognizedReflectionPattern", Justification = "Using GetType to test trimming")]`
109
+
- Pass an assembly-qualified name (`"ns.type, assembly.name"`) to `Type.GetType` as it searches only the executing assembly and corlib by default.
110
+
- There's no output indicating that a test has passed, so it's important to check that it's actually running (e.g. by inserting an artificial failure).
111
+
- If your test depends on any JSON serialization functionality, you'll probably need to disable the `System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault` feature switch.
112
+
- If your test validates that a type is being trimmed, it's good practice to write a dual test (sharing the same helpers) that validates that it is preserved (in a different scenario, of course) so that the trimming test doesn't accidentally pass because of (e.g.) a typo in the type name passed to `GetType`.
0 commit comments