|
2 | 2 |
|
3 | 3 | author: Sebastian Zug, Galina Rudolf & André Dietrich |
4 | 4 | email: sebastian.zug@informatik.tu-freiberg.de |
5 | | -version: 1.0.10 |
| 5 | +version: 1.0.11 |
6 | 6 | language: de |
7 | 7 | narrator: Deutsch Female |
8 | 8 | comment: Softwarefehler, Testen zur Qualitätssicherung, Planung von Tests, Konzepte und Umsetzung in dotnet |
@@ -109,7 +109,7 @@ Betrieb und Wartung: |
109 | 109 | + Die Schulung der Anwender wird vernachlässigt. |
110 | 110 | + Das Konfigurationsmanagement ist unzureichend. |
111 | 111 |
|
112 | | -<!-- |
| 112 | +<!--https://raw.githubusercontent.com/TUBAF-IfI-LiaScript/VL_Softwareentwicklung/refs/heads/master/19_Testen.md |
113 | 113 | style="width: 100%; max-width: 560px; display: block; margin-left: auto; margin-right: auto;" |
114 | 114 | --> |
115 | 115 | ```````````` |
@@ -791,3 +791,260 @@ reportgenerator "-reports:.coverage/**/*.cobertura.xml" "-targetdir:.coverage-re |
791 | 791 | Das Argument "XPlat Code Coverage" bezieht sich auf das Zwischenformat der Darstellung. Das `./.coverage` dient zur Angabe des Verzeichnisses, in dem die Ergebnisse gespeichert werden sollen. Wenn keines angegeben wird, wird standardmäßig ein TestResults-Verzeichnis innerhalb jedes Projekts verwendet. `reportgenerator` erzeugt dann die entsprechende html-Repräsentation. |
792 | 792 |
|
793 | 793 |  |
| 794 | + |
| 795 | + |
| 796 | +> Im Projektordner finden Sie die gesamte Testimplementierung. Diese wurde um eine Python Applikation erweitert, die eine Sprachübergreifende Nutzung einer Csharp Bibliothek illustriert. |
| 797 | +
|
| 798 | +## Fazit |
| 799 | + |
| 800 | +> Testen auf Modulebene - reicht das aus? |
| 801 | +
|
| 802 | +Testen auf Modulebene ist ein wichtiger Bestandteil der Softwareentwicklung, aber es ist nicht ausreichend, um die Qualität eines gesamten Systems zu gewährleisten. Es deckt nur die kleinsten Einheiten ab und stellt sicher, dass diese korrekt funktionieren. Allerdings können Fehler in der Interaktion zwischen Modulen oder in der Systemintegration unentdeckt bleiben. |
| 803 | + |
| 804 | + |
| 805 | +## Erweiterung |
| 806 | + |
| 807 | +| Testart | Fokus | Isolation | Beispiel | |
| 808 | +| ---------------------- | ---------------- | ----------- | --------------------------------- | |
| 809 | +| Unit-Test | Methode/Funktion | vollständig | `Addiere(int a, int b)` | |
| 810 | +| Modul-/Komponententest | Klasse/Modul | teilweise | `Warenkorb.AddArtikel()` | |
| 811 | +| Integrationstest | mehrere Module | gering | Bestellung -> Lager -> Versand | |
| 812 | +| Systemtest | gesamte App | keine | App starten und Bestellung testen | |
| 813 | + |
| 814 | +### Testen auf Modulebene |
| 815 | + |
| 816 | + {{0-1}} |
| 817 | +**************************************************************** |
| 818 | + |
| 819 | +Modul oder Komponententests sind Tests, die sich auf einzelne Module oder Komponenten einer Software konzentrieren. Sie überprüfen die Funktionalität und das Verhalten dieser Module isoliert von anderen Teilen des Systems. |
| 820 | + |
| 821 | +```csharp |
| 822 | +using Xunit; |
| 823 | + |
| 824 | +public class WarenkorbTests { |
| 825 | + [Fact] |
| 826 | + public void Test_Gesamtpreis_fuer_mehrere_Artikel() { |
| 827 | + // Arrange |
| 828 | + var korb = new Warenkorb(); |
| 829 | + korb.Hinzufügen(new Artikel { Name = "Buch", Preis = 10.0m }); |
| 830 | + korb.Hinzufügen(new Artikel { Name = "Stift", Preis = 2.0m }); |
| 831 | + |
| 832 | + // Act |
| 833 | + var gesamt = korb.Gesamtpreis(); |
| 834 | + |
| 835 | + // Assert |
| 836 | + Assert.Equal(12.0m, gesamt); |
| 837 | + } |
| 838 | +} |
| 839 | +``` |
| 840 | + |
| 841 | +**************************************************************** |
| 842 | + |
| 843 | + {{1-2}} |
| 844 | +**************************************************************** |
| 845 | + |
| 846 | + |
| 847 | +In der realen Software bestehen viele Klassen aus Abhängigkeiten zu anderen Komponenten – z. B. Datenbanken, externe Dienste oder Services. |
| 848 | + |
| 849 | +**Mocks** sind Test-Doubles, mit denen du diese Abhängigkeiten im Test ersetzen kannst, um: |
| 850 | + |
| 851 | +- das Verhalten der Komponente isoliert zu testen |
| 852 | +- kontrollierte Rückgaben zu simulieren |
| 853 | +- Seiteneffekte zu vermeiden |
| 854 | + |
| 855 | + |
| 856 | +__Warum ist Mocking wichtig?__ |
| 857 | + |
| 858 | +Ohne Mocks würdest du in jedem Testfall: |
| 859 | + |
| 860 | +- eine echte Datenbank ansprechen |
| 861 | +- eine E-Mail versenden |
| 862 | +- einen Webservice kontaktieren |
| 863 | + |
| 864 | +Das macht Tests langsam, fehleranfällig und unzuverlässig. |
| 865 | + |
| 866 | +__Best Practices beim Mocking__ |
| 867 | + |
| 868 | +- Mocke nur explizite Abhängigkeiten (nicht alles!) |
| 869 | +- Nutze Interfaces oder abstrakte Klassen als Testanker |
| 870 | +- Verwende `.Setup(...)` nur für erwartetes Verhalten |
| 871 | +- Nutze `.Verify(...)` zur Kontrolle von Aufrufen (z. B. ob ein E-Mail-Versand ausgelöst wurde) |
| 872 | + |
| 873 | +**************************************************************** |
| 874 | + |
| 875 | + {{2-3}} |
| 876 | +**************************************************************** |
| 877 | + |
| 878 | +Produktionscode: |
| 879 | + |
| 880 | +```csharp |
| 881 | +public interface IPreisDienst { |
| 882 | + decimal GibPreis(string artikelId); |
| 883 | +} |
| 884 | + |
| 885 | +public class Kasse { |
| 886 | + private readonly IPreisDienst _preisDienst; |
| 887 | + |
| 888 | + public Kasse(IPreisDienst preisDienst) { |
| 889 | + _preisDienst = preisDienst; |
| 890 | + } |
| 891 | + |
| 892 | + public decimal BerechneGesamtpreis(string artikelId, int menge) { |
| 893 | + var einzelpreis = _preisDienst.GibPreis(artikelId); |
| 894 | + return einzelpreis * menge; |
| 895 | + } |
| 896 | +} |
| 897 | +``` |
| 898 | + |
| 899 | +Testcode mit Mocking: |
| 900 | + |
| 901 | +```csharp |
| 902 | +using Moq; |
| 903 | +using Xunit; |
| 904 | + |
| 905 | +public class KasseTests { |
| 906 | + [Fact] |
| 907 | + public void BerechneGesamtpreis_mit_MockDienst() { |
| 908 | + // Arrange |
| 909 | + var mockDienst = new Mock<IPreisDienst>(); |
| 910 | + mockDienst.Setup(d => d.GibPreis("A1")).Returns(10.0m); |
| 911 | + |
| 912 | + var kasse = new Kasse(mockDienst.Object); |
| 913 | + |
| 914 | + // Act |
| 915 | + var gesamt = kasse.BerechneGesamtpreis("A1", 3); |
| 916 | + |
| 917 | + // Assert |
| 918 | + Assert.Equal(30.0m, gesamt); |
| 919 | + } |
| 920 | +} |
| 921 | +``` |
| 922 | + |
| 923 | +*************************************************************** |
| 924 | + |
| 925 | +### Integrationstests |
| 926 | + |
| 927 | +Ein **Integrationstest** prüft das **Zusammenspiel mehrerer Module oder Klassen**, z. B.: |
| 928 | + |
| 929 | +- Controller ↔ Service ↔ Datenbank |
| 930 | +- UI ↔ Backend ↔ API |
| 931 | +- Repository ↔ Domain-Logik |
| 932 | + |
| 933 | +> Ziel ist es, **Schnittstellenfehler** und **Zusammenarbeitsprobleme** zu erkennen – bevor das System als Ganzes getestet wird. |
| 934 | +
|
| 935 | +Produktionscode: |
| 936 | + |
| 937 | +```csharp |
| 938 | +// Domainmodell |
| 939 | +public class Artikel { |
| 940 | + public int Id { get; set; } |
| 941 | + public string Name { get; set; } |
| 942 | + public decimal Preis { get; set; } |
| 943 | +} |
| 944 | + |
| 945 | +// Repository |
| 946 | +public class ArtikelRepository { |
| 947 | + private readonly DbContext _ctx; |
| 948 | + public ArtikelRepository(DbContext ctx) => _ctx = ctx; |
| 949 | + |
| 950 | + public void Speichern(Artikel a) { |
| 951 | + _ctx.Add(a); |
| 952 | + _ctx.SaveChanges(); |
| 953 | + } |
| 954 | + |
| 955 | + public Artikel? Finde(int id) => _ctx.Set<Artikel>().Find(id); |
| 956 | +} |
| 957 | +``` |
| 958 | + |
| 959 | +Testcode mit Mocking: |
| 960 | + |
| 961 | +```csharp |
| 962 | +using Xunit; |
| 963 | +using Microsoft.EntityFrameworkCore; |
| 964 | + |
| 965 | +public class ArtikelRepositoryTests { |
| 966 | + [Fact] |
| 967 | + public void Speichern_und_Lesen_von_Artikeln() { |
| 968 | + // Arrange: In-Memory-Kontext |
| 969 | + var options = new DbContextOptionsBuilder<DbContext>() |
| 970 | + .UseInMemoryDatabase("TestDB") |
| 971 | + .Options; |
| 972 | + |
| 973 | + using var ctx = new DbContext(options); |
| 974 | + var repo = new ArtikelRepository(ctx); |
| 975 | + var artikel = new Artikel { Name = "Test", Preis = 5.0m }; |
| 976 | + |
| 977 | + // Act |
| 978 | + repo.Speichern(artikel); |
| 979 | + var gelesen = repo.Finde(artikel.Id); |
| 980 | + |
| 981 | + // Assert |
| 982 | + Assert.NotNull(gelesen); |
| 983 | + Assert.Equal("Test", gelesen?.Name); |
| 984 | + } |
| 985 | +} |
| 986 | +``` |
| 987 | + |
| 988 | +> Anstatt einen echten Datenbankserver zu verwenden, nutzen wir eine **In-Memory-Datenbank** für die Tests. Diese ermöglicht aber auch wesentlich konkrete Umsetzungen als die Mock-Objekte, da sie die tatsächliche Datenbank-Logik "simuliert". |
| 989 | +
|
| 990 | +### Testen auf Systemebene |
| 991 | + |
| 992 | +Ein **Systemtest** überprüft das **gesamte Systemverhalten** aus Sicht des Endnutzers. |
| 993 | +Dabei wird die gesamte Anwendung als Black Box getestet – **alle Komponenten, Module und Schnittstellen** sind integriert. |
| 994 | + |
| 995 | +> Ziel: Sicherstellen, dass das System als Ganzes die Anforderungen erfüllt. |
| 996 | +
|
| 997 | +--- |
| 998 | + |
| 999 | +### Abgrenzung zu anderen Tests |
| 1000 | + |
| 1001 | +| Testart | Fokus | Perspektive | |
| 1002 | +| ---------------- | ----------------------------- | --------------- | |
| 1003 | +| Unittest | Einzelne Methode | Entwickler | |
| 1004 | +| Komponententest | Klasse/Modul | Entwickler | |
| 1005 | +| Integrationstest | Zusammenspiel mehrerer Module | Entwickler | |
| 1006 | +| **Systemtest** | Gesamtsystem | **Nutzer / Tester** | |
| 1007 | + |
| 1008 | + |
| 1009 | +### Eigenschaften von Systemtests |
| 1010 | + |
| 1011 | +- Arbeiten mit **realen oder simulierten Datenbanken, Schnittstellen, UI** |
| 1012 | +- Testen **End-to-End-Szenarien** (z. B. Anmeldung, Bestellung, Zahlung) |
| 1013 | +- Häufig **automatisiert** mit Tools wie Selenium, Playwright oder TestServer |
| 1014 | +- Können auch **manuell** durchgeführt werden (z. B. nach Checklisten) |
| 1015 | + |
| 1016 | + |
| 1017 | +## Vergleich |
| 1018 | + |
| 1019 | +| Kriterium | **Methodentest** (Unit Test) | **Komponententest** | **Integrationstest** | **Systemtest** | |
| 1020 | +| ----------------------- | ---------------------------------- | ---------------------------------------------- | -------------------------------------------- | ------------------------------------------- | |
| 1021 | +| **Testobjekt** | Einzelne Methode oder Funktion | Klasse oder Modul mit internen Abhängigkeiten | Zusammenspiel mehrerer Komponenten/Module | Gesamtsystem (End-to-End) | |
| 1022 | +| **Ziel** | Korrektheit der kleinsten Einheit | Zusammenarbeit mehrerer Funktionen | Schnittstellen und Zusammenarbeit testen | Verhalten des Systems aus Sicht des Nutzers | |
| 1023 | +| **Abhängigkeiten** | Werden meist gemockt oder isoliert | Können teilweise eingebunden oder ersetzt sein | Echte Implementierungen (z. B. DB, Services) | Realitätsnahe, echte Umgebung | |
| 1024 | +| **Beispiel** | `CalculateSum(int a, int b)` | `UserService` mit `EmailService` | `UserController` ↔ `UserRepository` (mit DB) | REST-API ↔ Datenbank ↔ Frontend | |
| 1025 | +| **Tools** | xUnit, NUnit | xUnit + Moq/Fakes | xUnit + InMemory DB / Testcontainers | Selenium, Postman, TestServer | |
| 1026 | +| **Laufzeit** | Sehr kurz | Mittel | Mittel bis lang | Lang | |
| 1027 | +| **Testgeschwindigkeit** | 🔵 Schnell | 🟡 Mittel | 🟡 Mittel | 🔴 Langsam | |
| 1028 | +| **Zuverlässigkeit** | Hoch (bei guter Isolation) | Mittel (Abhängigkeiten können stören) | Mittel (mehr Fehlerquellen möglich) | Niedriger (viele beteiligte Komponenten) | |
| 1029 | +| **Fehlersuche** | Sehr präzise | Eingrenzbar | Eingrenzbar mit Fokus auf Schnittstellen | Schwieriger (viele beteiligte Komponenten) | |
| 1030 | +| **CI/CD-Einsatz** | Immer | Häufig | Häufig / nach jedem Build | Selektiv / nachts | |
| 1031 | + |
| 1032 | +Andere Darstellung |
| 1033 | + |
| 1034 | +```ascii |
| 1035 | + +---------------------------+ |
| 1036 | + | Systemtests | 🔴 Langsam, teuer, realistisch |
| 1037 | + +---------------------------+ |
| 1038 | + +-----------------------+ |
| 1039 | + | Integrationstests | 🟡 Echte Zusammenarbeit prüfen |
| 1040 | + +-----------------------+ |
| 1041 | + +-------------------+ |
| 1042 | + | Komponententests | 🟡 Module mit Abhängigkeiten |
| 1043 | + +-------------------+ |
| 1044 | + +---------------+ |
| 1045 | + | Unittests | 🔵 Schnell, stabil, viele |
| 1046 | + +---------------+ |
| 1047 | +
|
| 1048 | +> 🔺 Je weiter oben, desto aufwändiger |
| 1049 | +> 🔻 Je weiter unten, desto mehr Tests sollten existieren . |
| 1050 | +``` |
0 commit comments