2009-08-18 12 views
19

Sto cercando di implementare il test delle unità per l'aproject, utilizza un progetto di "utilità" legacy che è disseminato di metodi statici e molte delle classi sono finali oi loro metodi sono definitivi. Non sono in grado di aggiornare il progetto precedente.Come posso testare i metodi finali e statici di un progetto di utilità?

JMock e EasyMock si strozzano entrambi sui metodi finali e non vedo un buon modo per testare le chiamate statiche. Quali tecniche ci sono per testarle?

+0

C'è qualche ragione per cui è necessario utilizzare un framework Mock? –

+0

Sì, le chiamate al metodo utilizzano le proprietà JNDI per connettersi al database e JMS, non voglio implementare tutti i pezzi per il mio test. –

+0

Sei in grado di rifattorizzare uno qualsiasi dei codici legacy per aiutarti? –

risposta

21

Se siete in grado di refactoring del codice, è possibile avvolgere le chiamate ai metodi finali/statici in semplici metodi di istanza, ad esempio:

protected Foo doBar(String name) { 
    return Utility.doBar(name); 
} 

Questo consente di ignorare il metodo di involucro in unit test per restituire un'istanza simulata di Foo.

In alternativa è possibile utilizzare Powermock, che si estende EasyMock (e Mockito) per consentire beffardo di metodi finali e statiche:

PowerMock è un framework che si estendono altre librerie finte come EasyMock con funzionalità più potenti. PowerMock utilizza una manipolazione personalizzata del classloader e del codice byte per abilitare il mocking di metodi statici, costruttori, classi e metodi finali, metodi privati, rimozione di inizializzatori statici e altro.

Ecco un test example beffardo un ultimo metodo statico, l'esempio mostra come prendere in giro alcuni altri tipi troppo:

@Test 
public void testMockStaticFinal() throws Exception { 
    mockStatic(StaticService.class); 
    String expected = "Hello altered World"; 
    expect(StaticService.sayFinal("hello")).andReturn("Hello altered World"); 
    replay(StaticService.class); 

    String actual = StaticService.sayFinal("hello"); 

    verify(StaticService.class); 
    assertEquals("Expected and actual did not match", expected, actual); 

    // Singleton still be mocked by now. 
    try { 
     StaticService.sayFinal("world"); 
      fail("Should throw AssertionError!"); 
    } catch (AssertionError e) { 
     assertEquals("\n Unexpected method call sayFinal(\"world\"):", 
      e.getMessage()); 
    } 
} 
+0

+1 per PowerMock poiché il refactoring è fuori questione. –

+0

questo mi sembra quello che mi serve, per sapere se funziona in una build di Maven? –

+0

Non l'ho ancora provato, ma sembra così: http://code.google.com/p/powermock/wiki/EasyMock_maven –

5

Come su un livello di indirezione/Dependency Injection?

Poiché il progetto di utilità legacy è una dipendenza, creare un'interfaccia per separarlo dal codice. Ora la tua implementazione reale/produttiva di questa interfaccia delega ai metodi di utilità legacy.

public LegacyActions : ILegacyActions 
{ 
    public void SomeMethod() { // delegates to final/static legacy utility method } 
} 

Per i test, è possibile creare un modello di questa interfaccia ed evitare l'interazione con il programma di utilità thingie legacy.

1

Se il metodo non refactorable utilizza qualcosa come JNDI per connettersi a un altro servizio, prenderei in considerazione l'avvio di un servizio JDNI e il popolamento con stub che controlli. È un dolore ma relativamente semplice. Può significare configurare un database o un listener JMS o qualsiasi altra cosa, ma dovrebbe esserci un'implementazione java leggera da poter inserire nei test.

+0

Questo va bene per i test di integrazione, ma i test unitari non dovrebbero avere bisogno di un database –

+0

Potresti essere in grado di prendere in giro il database e iniettarlo nella JNDI. – extraneon

+1

@Rich Venditore: Sono d'accordo ma se tu avessi delle uova potresti avere pancetta e uova, se avessi del bacon. Con ciò intendo che la domanda originale affermava che non poteva refactoring il codice e voleva aggiungere test. A volte devi lavorare con quello che hai, non quello che vuoi. –

3

JMockit consente di simulare metodi statici e classi finali. Presumo che usi qualche classloadin-fu, anche se non l'ho davvero studiato.

aspettative JMockit API consente aspettative da impostare su qualsiasi tipo di invocazione di metodi (su interfacce, classi astratte calcestruzzo finale or classi non definitivi, e su statici metodi), nonché sulla classe istanza tramite qualsiasi costruttore .

1

Come già indicato, è possibile utilizzare JMockit. Un esempio:

@Test 
public void mockStaticAndFinalMethods(final LegacyService mock) 
{ 
    new NonStrictExpectations() 
    { 
     { 
     LegacyService.staticMethod("hello"); result = "Hello altered World"; 
     } 
    }; 

    String actual = LegacyService.staticMethod("hello"); 
    new LegacyService().finalMethod(123, "test"); 

    assertEquals("Hello altered World", actual); 

    new Verifications() 
    { 
     { 
     mock.finalMethod(123, "test"); // verify this call occurred at least once 
     } 
    }; 
} 

Il progetto home page JMockit contiene un confronto con PowerMock, per chi fosse interessato.

-1

JMock insieme a JDave può prendere in giro metodi e classi finali, se necessario. Here sono istruzioni. Detto questo tratterò questo codice legacy (come altri hanno già suggerito) come dipendenza esterna e costruirò interfacce e deriderà quelle. È un altro livello di riferimento indiretto, ma dal momento che non è possibile modificare quel codice legacy, sembra essere ragionevole.

Problemi correlati