2011-10-18 16 views
6

Mi pregunta es muy similar a la cuestión planteada en Injecting Mockito mocks into a Spring bean. De hecho, creo que la respuesta aceptada podría funcionar para mí. Sin embargo, tengo un problema con la respuesta, y luego alguna explicación adicional en caso de que la respuesta no sea, de hecho, mi respuesta.inyección de prueba Spring + Mockito

Así que seguí el enlace en la publicación mencionada anteriormente al sitio web de Springockito. Alteré mi test-config.xml incluir algo similar a lo siguiente:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mockito="http://www.mockito.org/spring/mockito" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.mockito.org/spring/mockito http://www.mockito.org/spring/mockito.xsd"> 

... 

    <mockito:mock id="accountService" class="org.kubek2k.account.DefaultAccountService" /> 
... 
</beans> 

Parece que hay algo mal con el www.mockito.org redirección actualmente, así que encontré el código XSD en https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd y una alteración de la entrada final en xsi: schemaLocation a punto a este enlace bitbucket.

Correr mvn test entonces produjo el siguiente error (nuevas líneas añadidas para facilitar la lectura):

Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: 
    Line 43 in XML document from class path resource [spring/test-context.xml] is invalid; 
    nested exception is org.xml.sax.SAXParseException; lineNumber: 43; columnNumber: 91; 
    The prefix "mockito" for element "mockito:mock" is not bound. 

Así que la pregunta sobre Springockito es: ¿Es posible incluir más de esto? ¿Qué me estoy perdiendo?

Ahora, a la explicación más ...

que tienen una interfaz cuya aplicación que estoy tratando de prueba:

public interface MobileService { 
    public Login login(Login login); 
    public User getUser(String accessCode, Date birthDate); 
} 

La aplicación contiene un DAO que la primavera @Autowire s en para mí :

@Service 
public class MobileServiceImpl implements MobileService { 
    private MobileDao mobileDao; 

    @Autowired 
    public void setMobileDao(MobileDao mobileDao) { 
     this.mobileDao = mobileDao; 
    } 
} 

no quiero alterar mi interfaz para incluir un método setMobileDao, debido a que el código sería la adición de sólo para mantener a mi unidad prueba. Estoy tratando de burlarme del DAO ya que el SUT real aquí es el ServiceImpl. ¿Cómo puedo conseguir esto?

Respuesta

9

No desea probar su interfaz: no contiene ningún código. Desea probar su implementación. Entonces el colocador está disponible. Solo úselo:

@Test 
public void testLogin() { 
    MobileServiceImpl toTest = new MobileServiceImpl(); 
    toTest.setMobileDao(mockMobileDao); 
    // TODO call the login method and check that it works as expected. 
} 

No necesita un contexto de primavera. Simplemente instale su servicio POJO, inyecte dependencias ficticias manualmente y pruebe los métodos que desea probar.

+1

@Mike Estoy de acuerdo, solo prueba la implementación. No tiene sentido tener un contexto de primavera para una prueba de ** unidad **. Y, por cierto, Mockito ofrece un mecanismo de inyección de dependencia trivial con una combinación de anotaciones '@ Mock' y' @ InjectMocks'. Debería ver sus respectivos [javadoc] (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html). – Brice

0

usted tiene tres opciones para definir su DAO simulacro:

  1. probar la aplicación - lo que da una costura para su maqueta a través del método setDao. (como respuesta de JB)
  2. Agregue el método setDedato a la interfaz, no deseado ya que no desea agregar código solo para respaldar sus pruebas.
  3. Agregue un constructor a la clase impl para aceptar el dao - no deseado por el mismo motivo que el # 2.

Si desea hacer el n. ° 3, deberá agregar un constructor al MobileService que acepte MobileDao.

public MobileServiceImpl(MobileDao mobileDao) { 
    this.mobileDao = mobileDao; 
} 

A continuación, la prueba se verá así:

import static org.mockito.Mockito.verify; 
import static org.mockito.Mockito.*; 

import java.util.Date; 

import org.junit.Before; 
import org.junit.Test; 

public class MobileServiceImplTest { 

    private MobileService systemUnderTest; 

    private MobileDao mobileDao; 

    @Before 
    public void setup() { 
     mobileDao = mock(MobileDao.class); 
     systemUnderTest = new MobileServiceImpl(mobileDao); 
    } 

    @Test 
    public void testGetUser() { 
     //if you need to, configure mock behavior here. 
     //i.e. when(mobileDao.someMethod(someObject)).thenReturn(someResponse); 
     systemUnderTest.getUser("accessCode", new Date()); 

     verify(mobileDao).getUser("JeffAtwood"); 
    } 
} 

Tenga en cuenta que no se nos ha proporcionado los detalles de la MobileDao así que creé un método getUser que acepta una cadena.

Para hacer el paso de la prueba, su MobileServiceImpl solo necesitaría esto:

mobileDao.getUser("JeffAtwood"); 
+0

Al igual que agregar un 'setMobileDao' a la interfaz, agregar otro ctor para pasar el objeto DAO sería alterar el código para respaldar las pruebas unitarias. Según la respuesta de @ jb-nizet, si alterno mi prueba para no usar la interfaz sino la implementación, entonces ya tengo acceso al método 'setMobileDao'. – Mike

+0

Entendido que no desea agregar nada al código solo para respaldar las pruebas. Probar el impl en lugar de la interfaz es algo que también hice en el pasado;) Solo quería dar otra opción. –

0

El problema parece ser la ruta de clases no contiene frasco springockito real - Usted no tiene que cambiar la URL de - estos son solo los tokens que se usan internamente para la primavera, no se resuelven, todo lo que necesita es una nueva distribución Spring suficiente y springockito en classpath.

Kuba (creador de :) lib antes mencionado)

0

que tenía el mismo problema, yo quería utilización por springockito según sus wiki pero validaciones errores de tiro XML. Entonces, cuando intenté ir a las ubicaciones donde se suponía que debía estar xsd, eso no fue así. Así que leí esto y comencé a trabajar con esto:

xmlns:mockito="http://www.mockito.org/spring/mockito" 
xsi:schemaLocation="http://www.mockito.org/spring/mockito 
    https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd"> 

Pero cuando miraba este enlace, tenía un mal presentimiento. Me parece que no es un enlace estable permanente (debe verificar si estoy equivocado)

+0

Parece que el enlace está roto ahora. ¿Alguien tiene uno nuevo? – schoenk

1

Después de luchar con el problema de Springockito XSD, por un tiempo, encontré una solución mucho más simple. Deje primavera inyectar la maqueta para usted, utilizando un método de fábrica, es decir, en poner applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.gerrydevstory.mycoolbank.AccountsDAO"/> 
    </bean> 

    <bean class="com.gerrydevstory.mycoolbank.BankingService"/> 

</beans> 

donde se inyecta el grano AccountsDAO en la clase BankingService. El caso de prueba JUnit correspondiente es:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/BankingServiceTest.xml") 
public class BankingServiceTest { 

    @Autowired private BankingService bankingService; 
    @Autowired private AccountsDAO mockAccountsDAO; 

    @Test 
    public void testTransfer() throws Exception { 
    // Setup 2 accounts 
    Account acc1 = new Account(); 
    acc1.setBalance(800.00); 
    Account acc2 = new Account(); 
    acc2.setBalance(200.00); 

    // Tell mock DAO to return above accounts when 1011 or 2041 is queried respectively 
    when(mockAccountsDAO.findById(1011)).thenReturn(acc1); 
    when(mockAccountsDAO.findById(2041)).thenReturn(acc2); 

    // Invoke the method to test 
    bankingService.transfer(1011, 2041, 500.00); 

    // Verify the money has been transferred 
    assertEquals(300.00, acc1.getBalance(), 0.001); 
    assertEquals(700.00, acc2.getBalance(), 0.001); 
    } 
} 

Personalmente, me parece muy elegante y fácil de entender. Para más detalles, vea el original blog post.

Cuestiones relacionadas