2012-05-26 19 views
5

Estoy escribiendo una unidad de pruebas utilizando JUNIT + Mockito para probar un método como:que imita una llamada en un método público de una clase abstracta y sin la subclasificación de la clase abstracta, utilizando Mockito prefererably

public someObject methodUnderTest(){ 
    SomeObject obj = SomeAbstractClass.someMethod(); 

    if(obj!=null){ 
    obj.someOtherMethod(); 
    } 

    return someThing; 
} 

y me gustaría para burlarse de la llamada en abstract Class "SomeAbstractClass" mencionado en el fragmento de código anterior para que pueda verificar llamada en "obj" como:

verify(SomeAbstractClass).someMethod(); 
verify(obj).someOtherMethod(); 

he intentado usar características Mockito como: Mockito.CALLS_REAL_METHODS Mockito. RETURNS_MOCKS

pero no funcionan debido a dependencias no disponibles para SomeAbstractClass.

Nota:

1) SomeObject es una interfaz.

2) Necesito una técnica para probar el fragmento de código anterior. Estoy obligado a usar el fragmento de código anterior y no puedo cambiar el fragmento de código.

Respuesta

1

Supuesto: si escribe la prueba de la unidad, supongo que todavía puede modificar el método probado un poco.

Solución:

  1. extracto de llamada a un método estático para el método reemplazable:
public someObject methodUnderTest() { 
    SomeObject obj = getSomeObject(); 

    if(obj!=null){ 
     obj.someOtherMethod(); 
    } 

    return someThing; 
} 

protected SomeObject getSomeObject() { 
    return SomeAbstractClass.someMethod(); 
} 
  1. continuación, puede utilizar Mockito espía para burlarse parcialmente el objeto que en realidad la prueba:
private ClassUnderTest classUnderTest; 

@Before 
public void setUp() { 
    classUnderTest= new ClassUnderTest(); 
    classUnderTest = Mockito.spy(classUnderTest); 
} 

@Test 
public void test() { 
    SomeObject someObject = Mockito.mock(SomeObject.class); 
    when(classUnderTest.getSomeObject()).thenReturn(someObject); 
    classUnderTest.methodUnderTest(); 
    verify(someObject).someOtherMethod(); 
} 

@Test 
public void testNull() { 
    when(classUnderTest.getSomeObject()).thenReturn(null); 
    classUnderTest.methodUnderTest(); 
    verify(something); 
} 
+0

Gracias miheys por su ayuda. Hice exactamente lo mismo. –

1

Use clases anónimas:

public interface SomeObject { 
    public Object someOtherMethod(); 
} 

public abstract class SomeAbstractClass { 
    abstract SomeObject someMethod(); 
} 

@Test 
public void test() { 
    SomeAbstractClass target = new SomeAbstractClass() { 
     SomeObject someMethod() { 
      // some impl 
      SomeObject someObject = new SomeObject() { 
       public Object someOtherMethod() { 
        // some other impl 
       } 
      }; 
      return someObject; 
     } 
    }; 

    // now test target 
} 
+0

Gracias Bohemian, pero olvidé mencionar que SomeObject devuelto es una interfaz, así como "SomeAbstractClass.someMethod()" es un método público y estático. Por lo tanto, estoy obligado a implementar la interfaz "SomeObject", que no quiero hacer, ya que "SomeAbstractClass" y "SomeObject" son parte de una biblioteca de terceros que estoy usando en mi aplicación web. –

+0

También puede usar una clase anónima para una interfaz (como SomeObject); consulte la respuesta editada – Bohemian

2

Puede utilizar PowerMock para burlarse de los métodos estáticos y finales.

2

Parece que el problema es que el uso de CALLS_REAL_METHODS está aplicando a toda la clase, en el que realmente quiere burlarse cabo métodos específicos (es decir, hacer un "simulacro parcial"). Usted tiene dos opciones aquí, uno usando thenCallRealMethod y otra utilizando CALLS_REAL_METHODS y luego burlarse específicamente las llamadas que necesita:

public void testMethodUnderTest_mockSpecificThings() { 
    SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    when(myAbstractClass.someMethod()).thenReturn(foo); 
    when(myAbstractClass.methodUnderTest()).thenCallRealMethod(); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

public void testMethodUnderTest_makeSpecificRealCalls() { 
    SomeAbstractClass myAbstractClass = 
     Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    // overrides the default answer 
    when(myAbstractClass.someMethod()).thenReturn(myObject); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

estar prevenido que SomeAbstractClass de hecho nunca se crea una instancia, por lo que si usted confía en cualquier comportamiento en la clase abstracta constructor, como la inicialización de la variable, incluida la inicialización en línea donde se declaran los campos, deberá realizar esas llamadas de manera explícita.

Cuestiones relacionadas