2012-01-11 7 views
8

Предположим, что у меня есть следующий объект службыTesting поведение ничтожной метода

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); 
    } 
} 

Я хочу, чтобы проверить поведение метода «AddUser», когда длина имени пользователя составляет менее 8, а когда имя пользователя более чем 8 символ , Как подойти в модульном тесте UserService.addUser (...) и проверить его? Я знаю, используя assert(), но значение «пароль» недоступно вне метода addUser (...).

Я использую JUnit и Mockito.

ответ

6

Я придумал решение, после некоторого повторного посещения проблемы снова через несколько месяцев.

Идея заключается в наблюдении за пользователем объекта, который передается пользователю UserDao. Мы можем проверить значение имени пользователя, делая это, следовательно, блок кода тест:

@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); 
    } 
} 

Гийом фактически имел самый близкий ответ, но он ответил, используя JMock. Тем не менее, он дал мне идею о том, как это сделать, поэтому я думаю, что он заслуживает некоторого кредита.

-1

Самый простой способ извлечь ту часть, где у вас есть коррекции логики

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

имя пользователя в метод и проверить возвращаемое значение этого метода.

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

с этим вы можете передавать различные типы имени пользователя и проверять поведение вашего кода.

+0

Я думал об этом, но фактический случай состоит из нескольких методов. То, что я здесь написал, является более упрощенной версией фактического случая. –

+0

Несмотря на негатив. проголосовать Я все еще думаю, что это упростит проверку логики проверки и модификации имени пользователя в отдельности (отдельно от тестирования того, что передается в метод сохранения). Тем более, если эта логика имеет другие сложности. И я также думаю, что вам не нужно будет использовать насмешки для тестирования этой логики. – derdo

1

Вы испытываете побочные эффекты, но, к счастью, все, что вам нужно, передается dao.save(). Во-первых, создайте UserDao (с или без Mockito), затем вы можете использовать ReflectionTestUtils для установки dao в UserService, тогда вы можете проверить значения, переданные dao.save().

Что-то вроде:

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); 
} 

Или вы можете пользователь Mockito издеваться из Дао, если вы хотите.

+0

Это не макет, это заглушка. Проверьте, что: http://martinfowler.com/articles/mocksArentStubs.html – Guillaume

+0

Да, я знаю, но я использовал ту же терминологию, что и OP. Я изменил текст. –

+0

Я пробовал этот подход, используя Mockito, чтобы высмеять объект UserDao. К сожалению, ReflectionTestUtils всегда возвращает объект null userDao. Сделали что-то не так? –

0

Все зависит от способа реализации метода сохранения DAO.

Если вы на самом деле сохранения данных на жестком кодировкой хранилище, то вам, вероятно, нужно запросить само хранилище для значений вы intereseted в.

Если у вас есть базовый интерфейс, который называется, то вы должен иметь возможность настроить метод обратного вызова и получить фактическое значение, которое сохраняется.

Я никогда не использовал Mockito, так что я не могу дать вам точный код, который делает эту статью следует обратиться к этому:

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

0

Учитывать извлечения имени пользователя генерации логики, как зависимость от UserService.

interface UserNameGenerator { 
    Strign generate(); 
} 

Wire UserNameGenerator же, как UserDao. И изменить код:

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); 
    } 
} 

Далее создайте реализацию по умолчанию UserNameGenerator и переместить имя создания логики там.

Теперь вы можете легко проверить поведение, издеваясь над UserNameGenerator и UserDao.

Для проверки использования случая, когда имени пользователя является длиной менее 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)); 

Для проверки использования случая, когда имени пользователя является длиной больше 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

Использованием рамки насмешливой , В приведенном ниже примере используется JMock2, но он будет похож на EasyMock, Mockito и т. Д. Кроме того, вам нужно извлечь генерацию имени пользователя примерно в UsernameGenmerator, чтобы ее издеваться. Вам понадобится другой специальный тест для генератора имени пользователя.

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); 
} 

И UsernameGenerator вам нужен тест на длину возвращаемого пользователя:

@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()); 
} 

Конечно, в зависимости от «случайного» способа, вы можете проверить его специфическое поведение тоже. Помимо этого, вышеприведенные условия обеспечивают достаточный охват вашего кода.

Смежные вопросы