2012-01-11 17 views
8

Supongamos que tengo el siguiente objeto de servicioprobar el comportamiento del método de vacío

public class UserService { 

    @Autowired 
    private UserDao dao; 

    public void addUser(String username, String password) { 
     if (username.length() < 8) { 
      username = username + "random" ; // add some random string 
     } 
     User user = new User(username, password); 

     dao.save(user); 
    } 
} 

Quiero probar el comportamiento del método "addUser" cuando la longitud nombre de usuario es menor de 8 y cuando el nombre de usuario es más de 8 Char . ¿Cómo abordar en el test de unidad UserService.addUser (...) y verificarlo? Soy consciente de usar assert(), pero el valor "contraseña" no está disponible fuera del método addUser (...).

Uso JUnit y Mockito.

Respuesta

6

Encontré una solución, después de volver a visitar el problema nuevamente después de algunos meses.

La idea es observar al usuario del objeto que se está pasando a UserDao. Podemos inspeccionar el valor del nombre de usuario al hacer esto, por lo tanto, el código de prueba de unidad:

@RunWith(MockitoJUnitRunner.class) 
public class UserServiceTest { 
    @Mock 
    private UserDao dao; 

    @InjectMock 
    private UserService service; 

    @Test 
    public void testAddingUserWithLessThan8CharUsername() { 
     final String username = "some"; 
     final String password = "user"; 
     doAnswer(new Answer<Object>() { 
      @Override 
      public Object answer(InvocationOnMock invocationOnMock) throws Throwable { 
       Object[] args = invocationOnMock.getArguments(); 
       User toBeSaved = (User) args[0]; 
       Assert.assertEquals(username + "random", toBeSaved.getPassword()); 
       return null; 
      } 
     }).when(userDao).save(Matchers.any(User.class)); 
     service.addUser(username, password); 
    } 
} 

Guillaume realidad tenía la respuesta más cercana, pero él respondió usando jMock. Sin embargo, él me dio la idea de cómo lograr esto, así que creo que merece algo de crédito también.

-1

La manera más fácil es extraer la parte donde usted tiene la corrección lógica nombre de usuario

if (username.length() < 8) { 
    username = username + "random" ; // add some random string 
} 

en un método y probar el valor de retorno de ese método.

public string GetValidUsername(string userName){ 
    if (username.length() < 8) { 
     return username + "random" ; // add some random string 
    } 
    return username; 
} 

Con esto puede pasar diferentes tipos de nombre de usuario y probar el comportamiento de su código.

+0

Pensé en esto, pero el caso real ya está compuesto por varios métodos. Lo que he escrito aquí es la versión más simplificada del caso real. –

+0

A pesar del neg. voto Aún creo que hará las cosas más simples para probar la validación del nombre de usuario y la lógica de modificación de forma aislada (aparte de probar lo que se pasa al método de guardar). Aún más, si esa lógica tiene otras complejidades. Y también creo que no necesitarás usar ninguna burla para probar esa lógica. – derdo

1

Está probando efectos secundarios, pero, afortunadamente, todo lo que necesita se pasa al dao.save(). Primero, crea un UserDao (ya sea con o sin Mockito), luego puedes usar ReflectionTestUtils para establecer el dao en el UserService, luego puedes probar los valores que se pasan a dao.save().

Algo así como:

private class TestUserDao extends UserDao { 
    private User savedUser; 
    public void save(User user) { 
     this.savedUser = user; 
    } 
} 

@Test public void testMethod() { 
    UserService userService = new UserService(); 
    TestUserDao userDao = new TestUserDao(); 

    ReflectionTestUtils.setField(userService, "dao", userDao); 

    userService.addUser("foo", "bar"); 

    assertEquals("foo", userDao.savedUser.username.substring(0, 3)); 
    assertEquals("bar", userDao.savedUser.password); 
} 

O puede Mockito usuario para burlarse de la Dao si lo desea.

+0

Esto no es un simulacro, esto es un trozo. Verifique que: http://martinfowler.com/articles/mocksArentStubs.html – Guillaume

+0

Sí, lo sé, pero estaba usando la misma terminología que el OP. Cambié el texto. –

+0

He intentado este enfoque, usando Mockito para simular el objeto UserDao. Desafortunadamente, ReflectionTestUtils siempre devuelve un objeto de usuario null null. ¿Has hecho algo mal? –

0

Todo dependería de cómo se implemente el método de guardado de su DAO.

Si en realidad se está almacenando en un repositorio no modificable, entonces es probable que necesite para consultar el propio repositorio para los valores que también se interesaron en.

Si usted tiene una interfaz subyacente que se llama, entonces debería ser capaz de configurar un método de devolución de llamada y recuperar el valor real que se está guardando.

nunca he utilizado Mockito por lo que no podría darle código exacto lo que hace este artículo debe abordar lo siguiente:

Using Mockito, how do I intercept a callback object on a void method?

0

Considere la extracción de nombre de usuario de generación de la lógica como la dependencia de UserService.

interface UserNameGenerator { 
    Strign generate(); 
} 

alambre UserNameGenerator mismo que UserDao. Y cambiar el código para:

public class UserService { 

    @Autowired 
    private UserDao dao; 
    @Autowired 
    private UserNameGenerator nameGenerator; 

    public void addUser(String username, String password) { 
     if (username.length() < 8) { 
      username = nameGenerator.generate(); 
     } 
     User user = new User(username, password); 

     dao.save(user); 
    } 
} 

A continuación, cree la implementación predeterminada de UserNameGenerator y mover nombre de la generación de la lógica allí.

Ahora puede comprobar fácilmente el comportamiento burlándose de UserNameGenerator y UserDao.

Para comprobar caso de uso cuando nombre de usuario es longitud es menor que 8

String username = "123"; 
String password = "pass"; 

String generatedName = "random"; 

// stub generator 
when(nameGenerator.generate()).thenReture(generatedName); 

// call the method 
userService.addUser(username, password); 

// verify that generator was called 
verify(nameGenerator).generate(); 

verify(userDao).save(new User(generatedName, password)); 

Para comprobar caso de uso cuando nombre de usuario es longitud es mayor que 8

String username = "123456789"; 
String password = "pass"; 

String generatedName = "random"; 

// call the method 
userService.addUser(username, password); 

// verify that generator was never called 
verify(nameGenerator, never()).generate(); 

verify(userDao).save(new User(username, password)); 
1

Utilice un marco de burla . El siguiente ejemplo usa JMock2, pero sería similar con EasyMock, Mockito, etc. Además, necesita extraer la generación del nombre de usuario a algo así como UsernameGenmerator para poder simularlo. Necesita otra prueba específica para el generador de nombre de usuario.

private final Mockery mockery = new Mockery(); 
private final UserDao mockDao = mockery.mock(UserDao.class); 
private final UsernameGenerator mockUserNameGenerator = mockery.mock(UsernameGenerator.class); 

@Test 
public void addUserUsesDaoToSaveUser() { 
    final String username = "something"; 
    final String generatedUsername = "siomething else"; 
    final String password = "a password"; 
    mockery.checking(new Expectations() {{ 
     oneOf(mockUsernameGenerator).generateUsername(username); 
     will(returnValue(generatedUsername)); 
     oneOf(mockDao).save(new User(generatedUsername, password)); // assumes your User class has a "natueral" equals/hashcode 
    }}); 

    UserService userService = new UserService(); 
    userService.addUser(username, password); 
} 

Y para UsernameGenerator necesita prueba de la longitud del nombre de usuario devuelto:

@Test 
public void leavesUsernameUnchangedIfMoreThanEightChars() { 
    final String username = "123456789"; 
    final UsernameGenerator usernameGenerator = new UsernameGenerator(); 
    assertEquals(username, userGenerator.generateUsername(username)); 
} 

@Test 
public void addsCharactersToUsernameIfLessThanEightChars() { 
    final String username = "1234567"; 
    final UsernameGenerator usernameGenerator = new UsernameGenerator(); 
    assertEquals(8, userGenerator.generateUsername(username).length()); 
} 

Por supuesto, dependiendo de su método "al azar", es posible que desee probar su comportamiento específico también. Aparte de eso, lo anterior proporciona una cobertura deficiente para su código.

Cuestiones relacionadas