Durch einfache Techniken zu besserer Wartbarkeit des Codes
Dennis Neumann Digitale Bibliothek Software- und Serviceentwicklung
Entschärfung des "Änderungsproblems":
Automatisiertes Testen
leicht zu testender Code ist leichter zu warten
public class Person {
private String name;
public void setName(String newName) {
name = newName.trim();
}
public String getName() {
return name;
}
}
@Test
public void shouldRemoveWhitespace() {
Person personSut = new Person();
personSut.setName(" Alex ");
String storedName = personSut.getName();
assertEquals("Alex", storedName);
}
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
private Service srv = new Service();
// for unit tests
void setService(Service newSrv) {
srv = newSrv;
}
public void useService() {
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
private Service srv = new Service();
// for unit tests
void setService(Service newSrv) {
srv = newSrv;
}
public void useService() {
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
@Test
public void shouldSendStartMessage() {
// wie Produktivcode
Client clientSut = new Client();
// echten Service ersetzen
Service serviceMock = mock(Service.class);
clientSut.setService(serviceMock);
// wie Produktivcode
clientSut.useService();
// der eigentliche Test, "Sicherstellen"
verify(serviceMock).sendMessage("start");
}
verify(serviceMock).sendMessage("start")when(serviceMock.getCurrentYear()).thenReturn(3000)
when(serviceMock.sendMessage("start")).thenThrow(new ServiceIsRunningException())
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
private Service srv;
public Client() {
srv = new Service();
}
// for unit tests
Client(Service testSrv) {
srv = testSrv;
}
public void useService() {
srv.sendMessage("start");
//...
}
}
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
// keine Instanzvariable!
// for unit tests
Service createService() {
return new Service();
}
public void useService() {
Service srv = createService();
srv.sendMessage("start");
//...
}
}
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
private Provider serviceProvider = new Provider();
// for unit tests
void setProvider(Provider newProvider) {
serviceProvider = newProvider;
}
public void useService() {
Service srv = serviceProvider.getService("local");
srv.sendMessage("start");
//...
}
}
public class Client {
public void useService() {
Service srv = new Service();
srv.sendMessage("start");
//...
}
}
// Aufruf im Produktivcode:
Client c = new Client();
c.useService();
public class Client {
public void useService(Service srv) {
srv.sendMessage("start");
//...
}
}
// ABER: Aufruf im Produktivcode:
Client c = new Client();
c.useService(new Service());