2009-07-29 24 views
15

¿Cómo puedo simular fácilmente un método estático en Java?¿Cómo puedo simular fácilmente un método estático en Java (jUnit4)

estoy utilizando Spring 2.5 y JUnit 4,4

@Service 
public class SomeServiceImpl implements SomeService { 

    public Object doSomething() { 
     Logger.getLogger(this.class); //a static method invoked. 
     // ... 
    } 
} 

no controlo el método estático que mi servicio necesita invocar así que no puedo refactor a ser más unidad comprobable. He usado el Log4J Logger como ejemplo, pero el método estático real es similar. No es una opción cambiar el método estático.

Hacer trabajo Grails, estoy acostumbrado a usar algo como:

def mockedControl = mockFor(Logger) 
mockControl.demand.static.getLogger{Class clazz-> … } 
… 
mockControl.verify() 

¿Cómo puedo hacer algo similar en Java?

+0

¿Se puede cambiar la implementación SomeServiceImpl? –

+0

No importa, Jon Skeet acaba de publicar lo que pensaba. ¡Me siento orgulloso! (pensando como Jon Skeet jeje) –

+0

Sí, puedo cambiar SomeServiceImpl, pero ¿por qué debería hacerlo? ¿Por qué la indirección adicional? –

Respuesta

0

Básicamente, no hay una manera fácil de hacer esto en Java + Spring 2.5 & JUnit 4.4 en este momento.

Aunque es posible refactorizar y abstraer la llamada estática, Refactorizar el código no es la solución que estaba buscando.

JMockit parecía que funcionaría, pero es incompatible con Spring 2.5 y JUnit 4.4.

+2

Se ha sugerido PowerMock y es capaz de simular métodos estáticos, por lo que hay una manera fácil – Richard

+0

PowerMock tiene pérdidas de memoria graves, que es lo que descubrimos después de ver el uso de memoria y la duración de nuestras compilaciones de Jenkins cuando usamos un plugin maven. que automáticamente ejecutará pruebas unitarias para garantizar la calidad de construcción. Es por eso que PowerMock es una mala opción. – Igor

+0

Mira esto, https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/ Puedes @RunWith (PowerMockRunner.class) y luego delegar en @PowerMockRunnerDelegate (SpringJUnit4ClassRunner .clase). Por supuesto, esto requerirá que trabajes con algunas versiones más recientes. – Yasin

14

¿Quiere decir que no puede controlar el código de llamada? Porque si controla las llamadas a el método estático pero no la implementación en sí, puede hacer que sea fácilmente comprobable. Cree una interfaz de dependencia con un único método con la misma firma que el método estático. Su implementación de producción simplemente llamará al método estático, pero cualquier cosa que actualmente llame al método estático llamará a través de la interfaz.

Puede simular esa interfaz de la forma habitual.

1
public interface LoggerWrapper { 
    public Logger getLogger(Class<?> c); 
    } 
public class RealLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return Logger.getLogger(c);} 
    } 
public class MockLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return somethingElse;} 
    } 
0

Esa es una de las razones por las que los métodos estáticos son malos.

Hemos rediseñado la mayoría de nuestras fábricas para tener también instaladores para poder establecer falsos objetos en ellas. De hecho, se nos ocurrió algo parecido a la inyección de dependencia, donde un único método funcionaba como una fábrica para todos nuestros singletons.

En su caso, agregar un método Logger.setLogger() (y almacenar ese valor) podría funcionar. Si es necesario, puede ampliar la clase de registrador y seguir el método getLogger con el suyo.

4

El marco JMockit promete permitir la burla de métodos estáticos.

https://jmockit.dev.java.net/

De hecho, hace algunas afirmaciones bastante llamativos, incluyendo que los métodos estáticos son una opción de diseño perfectamente válido y su uso no deben restringirse a causa de la insuficiencia de infraestructuras de prueba.

Independientemente de si estas afirmaciones son justificables, el marco de JMockit en sí es bastante interesante, aunque todavía tengo que probarlo.

+1

El uso de métodos estáticos siempre será polémico. Pero, ¿alguien puede argumentar realmente contra el uso juicioso de la palabra clave final? Considere, por ejemplo, lo que el libro "Java efectivo" tiene que decir al respecto (ítem 17). –

+1

Cuando analicé Usar JMockit, descubrí que Spring 2.5.x es incompatible con JUnit 4.5+, y que JMockit es compatible con JUnit 4.4 (y más abajo), vea http://jira.springframework.org/browse/SPR-5145. a través de http://stackoverflow.com/questions/693115/junit4-spring-2-5-asserts-throw-noclassdeffounderror –

+0

Así que JMockit está fuera de cuestión por ahora. –

0

Puede utilizar AspectJ para interceptar la llamada al método estático y hacer algo útil para su prueba.

+1

¿Cómo podría hacer eso? ¿Hay un ejemplo simple? –

1

Como otra respuesta mencionada anteriormente, JMockit puede simular métodos estáticos (y cualquier otra cosa, también).

Incluso tiene soporte directo para estructuras de registro. Por ejemplo, puede escribir:


@UsingMocksAndStubs(Log4jMocks.class) 
public class SomeServiceTest 
{ 
    // All test methods in this class will have any calls 
    // to the Log4J API automatically stubbed out. 
} 

El soporte para JUnit 4.4 se ha caído, sin embargo. JUnit 3.8, JUnit 4.5+ y TestNG 5.8+ son compatibles.

4

PowerMock tiene esta capacidad. También puede simular instancias de objetos dentro de la clase bajo prueba. Si su método probado llama al nuevo Foo(), puede crear un objeto simulado para ese Foo y reemplazarlo en el método que está probando.

Cosas como la supresión de constructores e inicializadores estáticos también son posibles. Todas estas cosas se consideran código no comprobable y, por lo tanto, no se recomienda hacer, pero si tiene código heredado, cambiarlo no siempre es una opción. Si se encuentra en esa posición, PowerMock puede ayudarlo.

Cuestiones relacionadas