{"id":3680,"date":"2023-09-12T12:34:55","date_gmt":"2023-09-12T12:34:55","guid":{"rendered":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?p=3680"},"modified":"2024-02-07T10:15:32","modified_gmt":"2024-02-07T10:15:32","slug":"test-driven-development-mit-blazor","status":"publish","type":"post","link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/","title":{"rendered":"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit"},"content":{"rendered":"\n<p>Im <a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/web-uis-mit-blazor\">vorherigen Artikel<\/a><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-alert-color\"> <\/mark><\/strong>wurde das Blazor-Framework vorgestellt, mit dem mit C# Web-UIs erstellt werden k\u00f6nnen. In diesem zweiten Artikel wollen wir uns eine Test-Bibliothek ansehen, die in den Top10 der NuGet-Downloads f\u00fcr Blazor rangiert&nbsp;<a href=\"#[1]\">[1]<\/a>.<\/p>\n\n\n\n<p>bUnit ist eine Bibliothek, mit der Unit Tests f\u00fcr Blazor-Komponenten erstellt werden. Sie ist seit 2021 als stabile Version verf\u00fcgbar&nbsp;<a href=\"#[2]\">[2]<\/a> und wird in der offiziellen Blazor-Dokumentation f\u00fcr Komponententests empfohlen&nbsp;<a href=\"http:\/\/[3]\">[3]<\/a>.<\/p>\n\n\n\n<p>Die Dokumentation f\u00fcr bUnit findet sich unter <a href=\"https:\/\/bunit.dev\/\">https:\/\/bunit.dev\/<\/a><\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Razor-Syntax f\u00fcr eine Web-UI mit C# statt JavaScript<\/h2>\n\n\n\n<p>Alle Bausteine einer Blazor-App sind Razor-Komponenten mit der Dateiendung <code>.razor<\/code>. Darin wird die Website oder ein Teil davon in der sogenannten Razor-Syntax beschrieben. Das ist ein Mix aus HTML, speziellem Razor-Markup und C#. CSS wird zum Stylen verwendet.<\/p>\n\n\n\n<p>Die klassische Blazor-Demo-Seite mit einem Z\u00e4hler sieht so aus:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@page \"\/counter\"\n\n&lt;PageTitle>Counter&lt;\/PageTitle>\n\n&lt;h1>Counter&lt;\/h1>\n\n&lt;p role=\"status\">Current count: @currentCount&lt;\/p>\n\n&lt;button class=\"btn btn-primary\" @onclick=\"IncrementCount\">Click me&lt;\/button>\n\n@code {\n    private int currentCount = 0;\n\n    private void IncrementCount()\n    {\n        currentCount++;\n    }\n}\n<\/pre>\n\n\n\n<p><em>Abbildung 1: Seite Counter.razor<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>In diesem Beispiel ist HTML und C# in einer Datei enthalten. F\u00fcr komplexere Komponenten ist es hilfreich, beides voneinander zu trennen, indem eine code-behind-Datei angelegt wird. Die Datei f\u00fcr unsere Komponente <code>Counter.razor<\/code> hei\u00dft dann <code>Counter.razor.cs<\/code>. Der Compiler verkn\u00fcpft die beiden Dateien automatisch miteinander, sodass uns IntelliSense beim Programmieren auf die Spr\u00fcnge hilft.<\/p>\n\n\n\n<p>Um die Code-Ausschnitte in diesem Artikel k\u00fcrzer zu halten, wurde f\u00fcr alle Beispiele Markup und C# mit einer code-behind-Datei getrennt.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Komponenten in Blazor: Razor Components<\/h2>\n\n\n\n<p>Um Elemente zu kapseln und wiederverwendbar zu machen, realisiert man Funktionalit\u00e4ten in Komponenten. Diese enthalten nur das Markup und den Code f\u00fcr eine einzelne Funktionalit\u00e4t. In der Website werden dann nur Komponenten eingef\u00fcgt und eventuell Parameter und Callbacks angebunden. Komponenten k\u00f6nnen in eine Library verschoben und als NuGet-Pakete bereitgestellt werden.<\/p>\n\n\n\n<p>Das Beispiel zeigt den gleichen Counter, nachdem er in einer Komponente CounterComponent.razor gekapselt wurde. Das visuelle Ergebnis im Browser ist gleich.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@page \"\/counter\"\n@using BlazorWasmTemplateApp.Components\n&lt;PageTitle>Counter&lt;\/PageTitle>\n\n&lt;h1>CounterComponent&lt;\/h1>\n&lt;CounterComponent\/>\n<\/pre>\n\n\n\n<p><em><em>Abbildung <\/em>2: Seite <code>Counter.razor<\/code> mit Komponente<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;p id=\"currentCount\" role=\"status\">Current count: @currentCount&lt;\/p>\n\n&lt;button id=\"incrementCountButton\" class=\"btn btn-primary\" @onclick=\"IncrementCount\">Click me&lt;\/button>\n<\/pre>\n\n\n\n<p><em><em>Abbildung <\/em>3: Markup f\u00fcr Counter-Komponente <code>CounterComponent.razor<\/code><\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using Microsoft.AspNetCore.Components;\n\nnamespace BlazorWasmTemplateApp.Components\n{\n    public partial class CounterComponent : ComponentBase\n    {\n        private int currentCount = 0;\n\n        private void IncrementCount()\n        {\n            currentCount++;\n        }\n    }\n}\n\n<\/pre>\n\n\n\n<p><em><em>Abbildung <\/em>4: Code f\u00fcr Counter-Komponente <code>CounterComponent.razor.cs<\/code><\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Unit Tests f\u00fcr die UI<\/h2>\n\n\n\n<p>\u00dcblicherweise wird die UI einer Anwendung mit Ende-zu-Ende-Tests (E2E) \u00fcberpr\u00fcft. In der Web-Entwicklung kommen daf\u00fcr Frameworks wie Selenium oder Playwright zum Einsatz. Diese Tests starten die gesamte Anwendung, rendern sie in einem Browser und f\u00fchren dann die Testschritte durch. In solchen Tests wird eine Funktionalit\u00e4t oft durch die gesamte Anwendung hindurch getestet. Aufgrund der Komplexit\u00e4t sind E2E-Tests oft wartungsintensiv und langsam. Daher ist die allgemein anerkannte Empfehlung, nur einige wenige E2E-Tests und viele Komponententests zu schreiben (Testpyramide, siehe <a href=\"#[4]\">[4]<\/a>).<\/p>\n\n\n\n<p>Wenn man die UI testgetrieben nach den Prinzipien von Test Driven Development (TDD) entwickelt oder eine Benutzeroberfl\u00e4che mit umfangreicher Logik programmiert, ben\u00f6tigt man viele Tests, die in kurzer Zeit ausgef\u00fchrt werden. Daher hat es in solchen F\u00e4llen Nachteile, wenn man ausschlie\u00dflich auf E2E-Tests setzt. bUnit-Tests sind das Gegenteil zu E2E-Tests, sie sind \u00fcbersichtlich, isoliert voneinander und vor allem schnell. Ein Test ben\u00f6tigt oft nur einige Millisekunden f\u00fcr die Ausf\u00fchrung und f\u00fchlt sich an wie ein Unit Test im Backend.<\/p>\n\n\n\n<p>bUnit ist auch eine gute Wahl, wenn man eine Bibliothek von Razor-Komponenten aufbaut. Nicht umsonst finden sich unter den Hauptsponsoren von bUnit Firmen wie Progress Telerik und Syncfusion, die u.a. Bibliotheken von Blazor-UI-Komponenten vertreiben.<\/p>\n\n\n\n<p>Unit Tests f\u00fcr die UI mit bUnit sind also eine gute Erg\u00e4nzung zu E2E-Tests, um Details der UI zu testen.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Erste Schritte mit bUnit<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Vorbereitungen<\/h3>\n\n\n\n<p>bUnit ist kein Framework, sondern auf die Test Runner xUnit, NUnit oder MSTest angewiesen. F\u00fcr die Beispiele in diesem Artikel wird xUnit verwendet. Die Ausf\u00fchrung der Tests erfolgt wie gewohnt \u00fcber die IDE oder \u00fcber die Kommandozeile mit <code>dotnet test<\/code>.<br>Da wir mit bUnit Razor-Komponenten testen wollen, m\u00fcssen wir das SDK in der Projektdatei unseres Testprojekts auf <code>Microsoft.NET.Sdk.Razor<\/code> \u00e4ndern. Details dazu finden sich in der bUnit-Dokumentation unter&nbsp;<a href=\"#[5]\">[5]<\/a>.<\/p>\n\n\n\n<p>bUnit ist mit Test-Projekten in der Version .NET Standard 2.1 und mit allen .NET Core-Versionen ab 3.1 kompatibel.<\/p>\n\n\n\n<p>Tests k\u00f6nnen in reinem C# oder in Razor-Syntax programmiert werden. Aus Gr\u00fcnden der Verst\u00e4ndlichkeit wird ausschlie\u00dflich die Variante mit C#-Code gezeigt. Mit Razor-Syntax ist es etwas einfacher, Parameter und Callbacks zu \u00fcbergeben und HTML direkt mit einem erwarteten Markup zu vergleichen. Da ein Vergleich von HTML aber zu schlecht wartbaren Tests f\u00fchrt, ist dieser Vorteil der Razor-Syntax in der Praxis unwichtig.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Der erste Test<\/h3>\n\n\n\n<p>Wie k\u00f6nnte ein Test unserer <code>CounterComponent <\/code>aussehen? Wir wollen \u00fcberpr\u00fcfen, ob unser Z\u00e4hler im Ausgangszustand 0 und nach einem Klick 1 anzeigt.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using Bunit;\n\nnamespace Tests\n{\n    public class CounterComponentTests : TestContext\n    {\n\n        [Fact]\n        public void CurrentCount_IsZero_ByDefault()\n        {\n            \/\/Arrange\n            var componentUnderTest = RenderComponent&lt;CounterComponent>();\n\n            \/\/Act\n            AngleSharp.Dom.IElement paragraph = componentUnderTest.Find(\"#currentCount\");\n\n            \/\/Assert\n            Assert.Equal(\"Current count: 0\", paragraph.InnerHtml);\n        }\n\n        [Fact]\n        public void CurrentCount_Increases_WhenButtonClicked()\n        {\n            \/\/Arrange\n            var componentUnderTest = RenderComponent&lt;CounterComponent>();\n            AngleSharp.Dom.IElement button = componentUnderTest.Find(\"#incrementCountButton\");\n\n            \/\/Act\n            button.Click();\n\n            \/\/Assert\n            AngleSharp.Dom.IElement paragraph = componentUnderTest.Find(\"#currentCount\");\n            Assert.Equal(\"Current count: 1\", paragraph.InnerHtml);\n        }\n    }\n}\n<\/pre>\n\n\n\n<p><em>Abbildung 5: Einfacher Test der <code>CounterComponent<\/code><\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Die generische Methode <code>RenderComponent&lt;TComponent&gt;()<\/code> mit <code>TComponent <\/code>als Typ der zu testenden Komponente erstellt ein Rendering. Dieses Rendering unserer <code>CounterComponent <\/code>mit seinen Attributen, Methoden und Eigenschaften entspricht der Darstellung der Komponente in einem Browser.<\/p>\n\n\n\n<p>Um Interaktionen durchzuf\u00fchren und den Inhalt des Renderings zu \u00fcberpr\u00fcfen, k\u00f6nnen wir Elemente mit der Methode <code>Find() <\/code>identifizieren. Diese Methode erwartet einen CSS-Selektor vom Typ <code>string <\/code>als Parameter. Ein CSS-Selektor ist ein Filter f\u00fcr die Elemente in einem HTML-DOM, der nach CSS-Klassen, Attributen, IDs oder HTML-Element-Typen filtern kann. Eine gute Referenz f\u00fcr CSS-Selektoren findet sich unter <a href=\"#[6]\">[6]<\/a>.<\/p>\n\n\n\n<p>Der CSS-Selektor \u201a<code>#<\/code>\u2018 filtert nach der ID des Elements. Der Selektor <code>#currentCount<\/code> filtert also das Element mit <code>id=\u201ccurrentCount\u201c <\/code>heraus, das in unserer Beispielkomponente den aktuellen Wert des Z\u00e4hlers enth\u00e4lt.<\/p>\n\n\n\n<p>Um zu ermitteln, ob unser Test erfolgreich ist, vergleichen wir den HTML-Inhalt mit einem erwarteten Text. Solche Tests sind fragil und wartungsintensiv, aber ein gutes Demo-Beispiel.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Komponenten mit Parametern testen<\/h3>\n\n\n\n<p>Wie sieht ein Test f\u00fcr eine Komponente mit Parametern aus? Dazu erweitern wir unsere <code>CounterComponent <\/code>um einen Parameter, mit dem wir den Startwert setzen k\u00f6nnen. Da wir unsere Komponente testgetrieben entwickeln wollen, f\u00fcgen wir als erstes einen neuen Test hinzu. Darin nutzen wir eine \u00dcberladung der Methode <code>RenderComponent() <\/code>mit der man per Lambda-Ausdruck Parameter an einen <code>ParameterBuilder <\/code>\u00fcbergibt.<\/p>\n\n\n\n<p>Da wir testgetrieben vorgehen und es den Parameter <code>StartValue <\/code>in unserer <code>CounterComponent <\/code>noch gar nicht gibt, ist unser Test jetzt noch nicht kompilierbar.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Fact]\npublic void CurrentCount_IsNotZero_WhenStartValueSet()\n{\n    \/\/Arrange\n    int startValue = 42;\n    var componentUnderTest = RenderComponent&lt;CounterComponent>(\n        parameterBuilder => parameterBuilder.Add(param => param.StartValue, startValue));\n\n    \/\/Act\n    AngleSharp.Dom.IElement paragraph = componentUnderTest.Find(\"#currentCount\");\n\n    \/\/Assert\n    Assert.Equal(\"Current count: \" + startValue, paragraph.InnerHtml);\n}\n<\/pre>\n\n\n\n<p><em>Abbildung 6: Test f\u00fcr unsere Komponente mit einem Parameter<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Damit der Test kompiliert, m\u00fcssen wir unsere Komponente <code>CounterComponent<\/code>erweitern. Im ersten Schritt f\u00fcgen wir das Property <code>StartValue <\/code>vom Typ <code>int<\/code>hinzu und versehen es mit dem Attribut <code>Parameter<\/code>. Jetzt kann unsere Komponente kompiliert werden. Anschlie\u00dfend f\u00fchren wir unseren neuen Test aus und sehen, dass er fehlschl\u00e4gt. Wir befinden uns also noch in der roten Phase des Red-Green-Refactor-Zyklus von TDD und m\u00fcssen die Implementierung anpassen. Dazu initialisieren wir unsere Variable <code>currentCount<\/code>in der Methode <code>OnParametersSet()<\/code>. Diese Methode wird von Blazor aufgerufen, nachdem die Parameter an eine Komponente \u00fcbergeben wurden. Jetzt k\u00f6nnen wir den Test erneut ausf\u00fchren und sehen, dass er erfolgreich ist. Wir sind also in der gr\u00fcnen Phase unseres TDD-Zyklus. Wir verzichten hier auf \u00c4nderungen in der Refactoring-Phase eines TDD-Zyklus.<\/p>\n\n\n\n<p>Die code-behind-Datei unserer Komponente sieht nun so aus:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using Microsoft.AspNetCore.Components;\n\nnamespace BlazorWasmTemplateApp.Components\n{\n    public partial class CounterComponent : ComponentBase\n    {\n        [Parameter]\n        public int StartValue { get; set; } = 0;\n\n        private int currentCount = 0;\n\n        protected override void OnParametersSet()\n        {\n            currentCount = StartValue;\n        }\n\n        private void IncrementCount()\n        {\n            currentCount++;\n        }\n    }\n}\n\n<\/pre>\n\n\n\n<p>Abbildung 7: Die um einen Parameter erweiterte Komponente<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Komponenten mit Events testen<\/h3>\n\n\n\n<p>Ein weiteres typisches Element von Razor-Komponenten sind Events. Nehmen wir an, dass unsere Website informiert werden m\u00f6chte, wenn sich der Wert unseres Z\u00e4hlers \u00e4ndert. Dazu erweitern wir unsere Tests abermals um den folgenden Test:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Fact]\npublic void OnCountIncremented_WasInvoked_WhenButtonClicked()\n{\n    \/\/Arrange\n    bool isEventInvoked = false;\n    var componentUnderTest = RenderComponent&lt;CounterComponent>(\n        parameterBuilder => parameterBuilder\n.Add(param => param.OnCountIncremented, () => isEventInvoked = true));\n\n    AngleSharp.Dom.IElement button = componentUnderTest.Find(\"#incrementCountButton\");\n\n    \/\/Act\n    button.Click();\n\n    \/\/Assert\n    Assert.True(isEventInvoked);\n}\n<\/pre>\n\n\n\n<p><em>Abbildung 8: Test f\u00fcr unsere Komponente mit einem Event<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Auch hier ist unser Test noch nicht kompilierbar. Daher erg\u00e4nzen wir unsere Komponente. Wir f\u00fcgen das neue Property <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\"><code>OnCountIncremented <\/code><\/code>vom Typ <code>EventCallback <\/code>hinzu und versehen es wie gehabt mit dem Attribute Parameter. Jetzt ist unser Test kompilierbar, schl\u00e4gt aber noch fehl. Damit im n\u00e4chsten Schritt unser neuer Test erfolgreich ist, rufen wir den Callback in der Methode <code>IncrementCount()<\/code> unserer Component auf.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using Microsoft.AspNetCore.Components;\n\nnamespace BlazorWasmTemplateApp.Components\n{\n    public partial class CounterComponent : ComponentBase\n    {\n        [Parameter]\n        public int StartValue { get; set; } = 0;\n\n        [Parameter]\n        public EventCallback OnCountIncremented { get; set; }\n\n        private int currentCount = 0;\n\n        protected override void OnParametersSet()\n        {\n            currentCount = StartValue;\n        }\n\n        private async Task IncrementCount()\n        {\n            currentCount++;\n            await OnCountIncremented.InvokeAsync();\n        }\n    }\n}\n\n<\/pre>\n\n\n\n<p><em>Abbildung 9: Die um einen Event erweiterte Komponente<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Subkomponenten<\/h3>\n\n\n\n<p>Razor-Komponenten k\u00f6nnen in sich wieder Razor-Komponenten enthalten (Subkomponenten). Mit bUnit ist es ist m\u00f6glich, diese Subkomponenten im DOM zu finden, mit Parametern zu versehen, erneut zu rendern und Asserts durchzuf\u00fchren. Ob solche Tests eine gute Idee sind, h\u00e4ngt vom Szenario ab. Um Abh\u00e4ngigkeiten zu verringern, ist es mit bUnit m\u00f6glich, Komponenten durch Test Doubles zu ersetzen. Das kann vor allem beim Einsatz von Bibliotheken eines Drittanbieters n\u00fctzlich sein.<\/p>\n\n\n\n<div style=\"height:11px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Dependency Injection<\/h3>\n\n\n\n<p>Neben Parametern und Events ist es in Razor-Komponenten \u00fcblich, Abh\u00e4ngigkeiten durch Dependency Injection zu injizieren. Das Blazor-Framework nutzt daf\u00fcr die Dependency Injection von ASP.NET Core. bUnit macht deshalb die <code>Services<\/code>-Kollektion in der Basisklasse <code>TestContext <\/code>verf\u00fcgbar, die aus ASP.NET Core bekannt ist. Dort k\u00f6nnen Test Doubles registriert werden, bevor die Komponente gerendert wird. F\u00fcr Abh\u00e4ngigkeiten wie <code>IJsRuntime<\/code>, <code>HttpClient<\/code>, <code>NavigationManager<\/code> etc., die den Komponenten normalerweise automatisch durch ASP.NET Core bereitgestellt werden, gibt es Anleitungen f\u00fcr Test Doubles in der Dokumentation von bUnit.<\/p>\n\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p>Mit bUnit gibt es auch f\u00fcr Blazor eine M\u00f6glichkeit, um Komponenten isoliert, schnell und ohne E2E-Tests unter die Lupe zu nehmen. Damit steht f\u00fcr Blazor-Entwickler ein wichtiges Tool zur Verf\u00fcgung, um mit Tests die Wartbarkeit der Blazor-App sicherzustellen. Au\u00dferdem wird es m\u00f6glich, auch die UI testgetrieben zu entwickeln. Damit steht Blazor auch in diesem Aspekt anderen SPA-Frameworks in nichts nach.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h1 class=\"wp-block-heading\">Quellen<\/h1>\n\n\n\n<p id=\"[1]\">[1] nuget.org. [Online]. Available: <a href=\"https:\/\/www.nuget.org\/packages?q=Tags%3A%22Blazor%22&amp;sortby=totalDownloads-desc\">https:\/\/www.nuget.org\/packages?q=Tags%3A%22Blazor%22&amp;sortby=totalDownloads-desc<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<p id=\"[2]\">[2] E. Hansen, \u201ebUnit Releases,\u201c GitHub, [Online]. Available:<a href=\" https:\/\/github.com\/bUnit-dev\/bUnit\/releases?page=3\"> https:\/\/github.com\/bUnit-dev\/bUnit\/releases?page=3<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<p id=\"[3]\">[3] L. Latham, R. Anderson und GitHubPang, \u201eTest Razor components in ASP.NET Core Blazor,\u201c Microsoft Learn, 04 April 2023. [Online]. Available: <a href=\"https:\/\/learn.microsoft.com\/en-us\/aspnet\/core\/blazor\/test\">https:\/\/learn.microsoft.com\/en-us\/aspnet\/core\/blazor\/test<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<p id=\"[4]\">[4] M. Cohn, Succeeding with Agile: Software Development Using Scrum, Addison-Wesley, 2009.<\/p>\n\n\n\n<p id=\"[5]\">[5] E. Hansen, \u201eCreating a new bUnit test project,\u201c bUnit, 7 April 2023. [Online]. Available: <a href=\"https:\/\/bunit.dev\/docs\/getting-started\/create-test-project.html\">https:\/\/bunit.dev\/docs\/getting-started\/create-test-project.html<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<p id=\"[6]\">[6] Refsnes Data, \u201eCSS Selector Reference,\u201c W3Schools, [Online]. Available: <a href=\"https:\/\/www.w3schools.com\/cssref\/css_selectors.php\">https:\/\/www.w3schools.com\/cssref\/css_selectors.php<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<p id=\"[7]\">[7] E. Hansen, \u201ebUnit Documentation,\u201c 2023. [Online]. Available: <a href=\"https:\/\/bunit.dev\/docs\/getting-started\/index.html\">https:\/\/bunit.dev\/docs\/getting-started\/index.html<\/a>. [Zugriff am 22 Juni 2023].<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.<\/p>\n","protected":false},"author":161,"featured_media":3558,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","footnotes":""},"categories":[656],"tags":[748,749,751,752,753,156,166,443,693,741,743,744,747],"topics":[745,770],"class_list":["post-3680","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-manufacturing-solutions","tag-industrie","tag-web-uis-2","tag-net8","tag-e2e-test","tag-komponententest","tag-ui","tag-test-driven-development","tag-net","tag-c-2","tag-blazor","tag-interaktive-web-frontends","tag-hosting-modelle","tag-web-frontends","topics-web-uis-mit-blazor","topics-manufacturing-solutions"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>ZEISS Digital Innovation Blog - Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit<\/title>\n<meta name=\"description\" content=\"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit\" \/>\n<meta property=\"og:description\" content=\"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/\" \/>\n<meta property=\"og:site_name\" content=\"Digital Innovation Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-09-12T12:34:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-07T10:15:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1333\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Michael Ro\u00dfberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit\" \/>\n<meta name=\"twitter:description\" content=\"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:site\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michael Ro\u00dfberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/\",\"name\":\"ZEISS Digital Innovation Blog - Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit\",\"isPartOf\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg\",\"datePublished\":\"2023-09-12T12:34:55+00:00\",\"dateModified\":\"2024-02-07T10:15:32+00:00\",\"author\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/b757e0f104e3655ec043238fc64b3120\"},\"description\":\"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.\",\"breadcrumb\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg\",\"width\":2000,\"height\":1333},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\",\"name\":\"Digital Innovation Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/b757e0f104e3655ec043238fc64b3120\",\"name\":\"Michael Ro\u00dfberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Bewerbungsfoto_quadratisch-e1691061552986-150x150.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Bewerbungsfoto_quadratisch-e1691061552986-150x150.jpg\",\"caption\":\"Michael Ro\u00dfberg\"},\"description\":\"Michael Ro\u00dfberg ist Softwareentwickler bei ZEISS Digital Innovation. Er arbeitet vorrangig mit .NET im Backend. Daneben bringt er im Bereich Manufacturing Solutions sein Wissen aus einem Studium der Automatisierungstechnik und f\u00fcnf Jahren als Automatisierungsingenieur ein.\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/michaelrossberg\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ZEISS Digital Innovation Blog - Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit","description":"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/","og_locale":"de_DE","og_type":"article","og_title":"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit","og_description":"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.","og_url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/","og_site_name":"Digital Innovation Blog","article_publisher":"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/","article_published_time":"2023-09-12T12:34:55+00:00","article_modified_time":"2024-02-07T10:15:32+00:00","og_image":[{"width":2000,"height":1333,"url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg","type":"image\/jpeg"}],"author":"Michael Ro\u00dfberg","twitter_card":"summary_large_image","twitter_title":"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit","twitter_description":"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.","twitter_image":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg","twitter_creator":"@ZEISS_di","twitter_site":"@ZEISS_di","twitter_misc":{"Verfasst von":"Michael Ro\u00dfberg","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/","name":"ZEISS Digital Innovation Blog - Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit","isPartOf":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage"},"image":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg","datePublished":"2023-09-12T12:34:55+00:00","dateModified":"2024-02-07T10:15:32+00:00","author":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/b757e0f104e3655ec043238fc64b3120"},"description":"Mit der Bibliothek bUnit k\u00f6nnen Komponententests f\u00fcr Blazor-Web-Frontends erstellt werden. Damit ist es m\u00f6glich, viele schnell ausf\u00fchrbare Tests zu erstellen. Anhand von Beispielen werden die ersten Schritte und die wichtigsten Features von bUnit vorgestellt.","breadcrumb":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#primaryimage","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild.jpg","width":2000,"height":1333},{"@type":"BreadcrumbList","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/test-driven-development-mit-blazor\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/"},{"@type":"ListItem","position":2,"name":"Test Driven Development f\u00fcr Blazor-Webkomponenten mit bUnit"}]},{"@type":"WebSite","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/","name":"Digital Innovation Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/b757e0f104e3655ec043238fc64b3120","name":"Michael Ro\u00dfberg","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Bewerbungsfoto_quadratisch-e1691061552986-150x150.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Bewerbungsfoto_quadratisch-e1691061552986-150x150.jpg","caption":"Michael Ro\u00dfberg"},"description":"Michael Ro\u00dfberg ist Softwareentwickler bei ZEISS Digital Innovation. Er arbeitet vorrangig mit .NET im Backend. Daneben bringt er im Bereich Manufacturing Solutions sein Wissen aus einem Studium der Automatisierungstechnik und f\u00fcnf Jahren als Automatisierungsingenieur ein.","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/michaelrossberg\/"}]}},"author_meta":{"display_name":"Michael Ro\u00dfberg","author_link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/michaelrossberg\/"},"featured_img":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2023\/08\/Beitragsbild-600x400.jpg","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Manufacturing Solutions<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Manufacturing Solutions<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Industrie<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Web-UIs<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">.NET8<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">E2E-Test<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Komponententest<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">UI<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Test Driven Development<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">.NET<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">C#<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Blazor<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">interaktive Web-Frontends<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Hosting-Modelle<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/manufacturing-solutions\/\" class=\"advgb-post-tax-term\">Web-Frontends<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Industrie<\/span>","<span class=\"advgb-post-tax-term\">Web-UIs<\/span>","<span class=\"advgb-post-tax-term\">.NET8<\/span>","<span class=\"advgb-post-tax-term\">E2E-Test<\/span>","<span class=\"advgb-post-tax-term\">Komponententest<\/span>","<span class=\"advgb-post-tax-term\">UI<\/span>","<span class=\"advgb-post-tax-term\">Test Driven Development<\/span>","<span class=\"advgb-post-tax-term\">.NET<\/span>","<span class=\"advgb-post-tax-term\">C#<\/span>","<span class=\"advgb-post-tax-term\">Blazor<\/span>","<span class=\"advgb-post-tax-term\">interaktive Web-Frontends<\/span>","<span class=\"advgb-post-tax-term\">Hosting-Modelle<\/span>","<span class=\"advgb-post-tax-term\">Web-Frontends<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 3\u00a0Jahren ago","modified":"Updated 2\u00a0Jahren ago"},"absolute_dates":{"created":"Posted on September 12, 2023","modified":"Updated on Februar 7, 2024"},"absolute_dates_time":{"created":"Posted on September 12, 2023 12:34 p.m.","modified":"Updated on Februar 7, 2024 10:15 a.m."},"featured_img_caption":"","series_order":"","_links":{"self":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/3680","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/users\/161"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/comments?post=3680"}],"version-history":[{"count":12,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/3680\/revisions"}],"predecessor-version":[{"id":3747,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/3680\/revisions\/3747"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media\/3558"}],"wp:attachment":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media?parent=3680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/categories?post=3680"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/tags?post=3680"},{"taxonomy":"topics","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/topics?post=3680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}