Skip to content

Commit 4610cb7

Browse files
redgp0glinkdotnet
authored andcommitted
docs: Add documentation on Testing Components that use native dependecies
1 parent 066dc80 commit 4610cb7

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

‎docs/site/docs/misc-test-tips.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,61 @@ With xUnit, this can be done as follows:
102102
## Easier HTML copying/pasting
103103

104104
When writing tests in `.cs` files, you may want to copy/paste HTML into C# strings from something like a Razor file, for example. This is tedious to do manually as you have to escape quotes and other special characters, for example `<div class="alert">` needs to be written as `"<div class=\"alert\">"`. The extension [SmartPaster](https://marketplace.visualstudio.com/items?itemName=martinw.SmartPaster) automatically escapes any characters that need to be escaped when it is used to copy strings.
105+
106+
## Testing components that use native dependencies
107+
108+
Blazor WebAssembly apps can call [native code compiled to WebAssembly](https://learn.microsoft.com/en-us/aspnet/core/blazor/webassembly-native-dependencies) through `[DllImport]`. bUnit does not run tests in WebAssembly. Tests run on the regular .NET runtime of the machine running them, the same way a Blazor Server app does. A native library that is only built for WebAssembly, for example C files added with `<NativeFileReference>`, is therefore not available in a test, and calling it throws a `DllNotFoundException`.
109+
110+
bUnit cannot load native code on its own, so there are two ways to test such components:
111+
112+
- **Ship a native binary for the operating system the tests run on.** If the library or NuGet package includes native binaries for Windows, Linux or macOS, for example in the [architecture-specific folders](https://learn.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks#architecture-specific-folders) of a NuGet package, the `[DllImport]` calls work in bUnit like in any other .NET app. Make sure there is a binary for every OS your tests run on, including CI.
113+
- **Wrap the native calls in a service.** Put the `[DllImport]` calls behind an interface, inject it into the component, and register a fake implementation in the test. The component can then be tested on any OS, and the native code is not called at all.
114+
115+
For example, a component that calls a native `fibonacci` function can depend on an `IFibonacci` service instead:
116+
117+
```csharp
118+
public interface IFibonacci
119+
{
120+
int Calculate(int n);
121+
}
122+
123+
public sealed class NativeFibonacci : IFibonacci
124+
{
125+
[DllImport("Test")]
126+
private static extern int fibonacci(int n);
127+
128+
public int Calculate(int n) => fibonacci(n);
129+
}
130+
```
131+
132+
The app registers the native implementation, for example with `builder.Services.AddSingleton<IFibonacci, NativeFibonacci>()`, and the component injects the interface:
133+
134+
```razor
135+
@inject IFibonacci Fibonacci
136+
137+
<p>@Fibonacci.Calculate(8)</p>
138+
```
139+
140+
The test registers a fake implementation instead, so the native library is never loaded:
141+
142+
```csharp
143+
public class FibonacciComponentTest : BunitContext
144+
{
145+
private sealed class FakeFibonacci : IFibonacci
146+
{
147+
public int Calculate(int n) => 21;
148+
}
149+
150+
[Fact]
151+
public void RendersCalculatedValue()
152+
{
153+
Services.AddSingleton<IFibonacci, FakeFibonacci>();
154+
155+
var cut = Render<FibonacciComponent>();
156+
157+
cut.MarkupMatches("<p>21</p>");
158+
}
159+
}
160+
```
161+
162+
Learn more about registering services in the test context on the <xref:inject-services> page.

0 commit comments

Comments
 (0)