Dirk Richter
Software-Entwicklung und Architektur

Probleme bei Unittests mit LoD und DIP


Inhaltsverzeichnis

Einleitung

Wenn das Law of Demeter (LoD) und das Dependency Inversion Principle (DIP) verletzte wird, ist es schwierig entkoppelte Komponententests zu schreiben:


Iteratives Refaktoring zur Verbesserung

Das Ziel ist, LoD und DIP schrittweise einzuführen, um saubere Komponententests zu ermöglichen.

1. Identifizieren von „Trainwrecks“ und direkten Abhängigkeiten

Suche nach Code-Stellen mit langen Methodenketten und direkten Instanziierungen/Verwendungen von Implementierungen.

1var city = order.customer.address.city; // LoD verletzt
2var repo = new OrderRepository();       // DIP verletzt

2. Fassaden und Methoden zur Kapselung einführen (LoD)

Erstelle in Klassen Methoden, die die Ketten abkürzen:

1public class Order {
2    public Customer Customer { get; set; }
3    public string GetCustomerCity() => Customer?.GetCity();
4}
5
6public class Customer {
7    public Address Address { get; set; }
8    public string GetCity() => Address?.City;
9}

Jetzt kann man order.GetCustomerCity() statt einer langen Kette verwenden.


3. Abhängigkeiten mit Interfaces abstrahieren (DIP)

Ersetze konkrete Typen durch Interfaces, z.B.:

 1public interface IOrderRepository {
 2    Order GetOrder(int id);
 3}
 4
 5public class OrderService {
 6    private readonly IOrderRepository _orderRepo;
 7    public OrderService(IOrderRepository orderRepo) {
 8        _orderRepo = orderRepo;
 9    }
10}

Dadurch kann man nun in Tests einfach ein Mock-Repository verwenden.


4. Dependency Injection verwenden

Verwende Dependency Injection Frameworks (wie Microsoft.Extensions.DependencyInjection) oder injiziere Abhängigkeiten über den Konstruktor. So ist der Code testbar und flexibel.

 1// NUnit Test
 2[Test]
 3public void GetOrder_ReturnsOrder() {
 4    var repoMock = new Mock<IOrderRepository>();
 5    repoMock.Setup(r => r.GetOrder(1)).Returns(new Order { /* ... */ });
 6    var service = new OrderService(repoMock.Object);
 7
 8    var result = service.GetOrder(1);
 9
10    Assert.IsNotNull(result);
11}

5. Iterativ vorgehen


6. Feedback und weitere Schritte


Zusammenfassung

Durch die Einführung von Law of Demeter und Dependency Inversion Principle wird Code modularer, die Komponenten werden unabhängiger und die Unittests werden einfacher, schneller und zuverlässiger. Man kann so systematisch von schwergewichtigen Systemtests zu zielgerichteten Komponententests wechseln.

#Unittests #Pattern #Cleancode