suo essere un paio di mesi da quando sto lavorando con il codice Java legacy, questa sono alcune delle cose che ho a che fare con: copertura di testQual è la differenza tra una Seam e una Mock?
- 0%.
- Enormi funzioni in occasioni ne ho persino viste alcune con più di 300 righe di codice.
- Un sacco di metodi privati e in alcuni casi metodi statici.
- Codice strettamente accoppiato.
All'inizio ero molto confuso, ho trovato difficile usare TDD nell'eredità. Dopo aver fatto i kata per settimane e aver esercitato le mie capacità di test e di presa in giro, la mia paura è diminuita e mi sento un po 'più fiducioso. Recentemente ho scoperto un libro chiamato: working effectivelly with legacy, non l'ho letto, ho solo dato un'occhiata al sommario e ho scoperto qualcosa di nuovo per me, The Seams. Apparentemente questo è molto importante quando si lavora nell'eredità.
Penso che questo Seams potrebbe aiutarmi molto a rompere le dipendenze e rendere testabile il mio codice in modo da poter aumentare la copertura del codice e rendere più preciso il test dell'unità.
Ma ho molti dubbi:
- Qualcuno può spiegare la differenza tra una cucitura ed un finto?
- Do Cuciture, rompono le regole TDD per quanto riguarda non toccare il codice di produzione, prima viene testato?
- Potresti mostrarmi un semplice esempio che mette a confronto una Seam and a Mock?
Qui di seguito vorrei incollare un esempio che ho fatto oggi in cui ho tentato di rompere una dipendenza con l'obiettivo di rendere il codice testabile e infine aumentare la copertura del test. Ti sarei grato se potessi commentare un po 'se vedessi degli errori?
In questo modo il codice legacy sembrava all'inizio:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(HttpServletRequest request) {
String [] values = request.getParameterValues(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
Se ho solo aggiungere una prova di unità che chiama questo metodo e afferma che uscita variabile, ha un certo valore dopo la chiamata, poi ho farebbe un errore, perché non sono un test unitario, farei test di integrazione. Quindi quello che devo fare, è eliminare la dipendenza che ho nel parametro. Per farlo, sostituisco il parametro con un'interfaccia:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(ParameterSource request) {
String [] values = request.getParameters(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
In questo modo l'interfaccia si presenta come:
public interface ParameterSource {
String[] getParameters(String name);
}
La prossima cosa che faccio, è creare la mia propria implementazione di tale interfaccia, ma io includono il HttpServletRequest come una variabile globale e implementare il metodo dell'interfaccia utilizzando il metodo/s di HttpServletRequest:
public class HttpServletRequestParameterSource implements ParameterSource {
private HttpServletRequest request;
public HttpServletRequestParameterSource(HttpServletRequest request) {
this.request = request;
}
public String[] getParameters(String name) {
return request.getParameterValues(name);
}
}
Fino a questo punto, penso che tutte le modifiche su il codice di produzione era sicuro. Ora creo il Seam nel mio pacchetto di test. Se ho capito bene, ora sono in grado di cambiare in sicurezza il comportamento della Seam.Questo è come lo faccio:
public class FakeParameterSource implements ParameterSource {
public String[] values = {"ParamA","ParamB","ParamC"};
public String[] getParameters(String name) {
return values;
}
}
E il passo finale, sarebbe quella di ottenere il sostegno della Seam, per testare la behavoir originale del metodo.
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import code.ABitOfLegacyRefactored;
import static org.hamcrest.Matchers.*;
public class ABitOfLegacySpecification {
private ABitOfLegacy aBitOfLegacy;
private String EMPTY = null;
@Before
public void initialize() {
aBitOfLegacy = new ABitOfLegacy();
}
@Test
public void
the_output_gets_populated_when_the_request_is_not_empty
() {
FakeParameterSource fakeParameterSource = new FakeParameterSource();
aBitOfLegacy.doSomeProcessing(fakeParameterSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
@Test(expected=NullPointerException.class)
public void
should_throw_an_exception_if_the_request_is_null
() {
aBitOfLegacy.doSomeProcessing(null);
}
}
Questo mi darà una copertura di prova del 100%. Apprezzo i tuoi pensieri:
- Ho interrotto la dipendenza correttamente?
- I test di unità mancano qualcosa?
- Cosa si può fare meglio?
- Questo esempio è abbastanza buono da aiutarmi a capire la differenza tra una Seam and a Mock?
- Come potrebbe un finto aiutarmi qui se non utilizzo la cucitura?
Le mock non sostituiscono le cuciture. – Gishu
Dovresti prendere quel libro e leggerlo. –