У меня есть этот красивый пейзаж передо мной, включая JSF, JUnit (4.11) и Mockito (1.10.19):Как издеваются недостижимые свойства класса третьей стороны через Mockito
@ManagedBean
@ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
//many other property setting and some JSF stuff
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
//A hell of a lot more code, proper getters/setters etc.
Вот тестовый класс:
public class UserAuthTest {
@Test
public void testCheckAuth() {
UserAuth bean = mock(UserAuth.class);
List<UserRole> mockRoleList = new ArrayList<UserRole>();
UserRole ur = mock(UserRole.class);
when(ur.getName()).thenReturn("SUPER_USER");
mockRoleList.add(ur);
when(bean.getRoleList()).thenReturn(mockRoleList);
assertEquals(true, bean.checkAuth());
}
Дело в том, Класс UserRole недоступен для меня, это еще одна часть проекта. У него нет конструктора без аргументов, и существующий конструктор требует других недостижимых классов и т. Д. Таким образом, я не могу его создать. В этих обстоятельствах все, что я хочу сделать, это заставить этот mock UserRole вести себя так, как возвращать необходимую String, когда вызывается метод getName().
Но, очевидно; когда я пытаюсь добавить этот объект userRole mock в список UserRoles, поведение, которое я пытался определить, не сохраняется вместе с объектом. И да, код выглядит довольно забавно в его текущей позиции. Хотя я оставил его там, чтобы узнать, что я должен сделать, чтобы достичь этой простой, маленькой цели.
Post-Edit: Я не мог решить проблему без изменения исходного компонента, хотя я следовал за предложением Джеффа ниже, и он хорошо работал как стратегия изоляции. Я не отметил это как лучший ответ, так как вопрос был «Как насмехаться над недостижимым классом третьей стороны?» (в текущем примере его класс UserRole) В конце концов, noob я понял, что «Издевательство над недостижимым третьим классом не отличается от насмешек над любым другим классом».
Вот как мне это удалось:
@ManagedBean
@ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
//the actual constructor including all JSF logic, highly dependent
}
UserAuth(List<UserRole> roleList) {
setRoleList(roleList);
//package private test-helper constructor which has no dependency on FacesContext etc.
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
А вот тестовый класс (внимание к итератору издеваться, то есть весь фокус):
public class UserAuthTest {
private UserRole mockRole;
private Iterator<UserRole> roleIterator;
private List<UserRole> mockRoleList;
private UserAuth tester;
@SuppressWarnings("unchecked")
@Before
public void setup() {
mockRoleList = mock(List.class);
mockRole = mock(UserRole.class);
roleIterator = mock(Iterator.class);
when(mockRoleList.iterator()).thenReturn(roleIterator);
when(roleIterator.hasNext()).thenReturn(true, false);
when(roleIterator.next()).thenReturn(mockRole);
tester = new UserAuth(mockRoleList);
}
@Test
public void testCheckAuth(){
when(mockRole.getName()).thenReturn("SUPER_USER");
assertEquals("SUPER_USER expected: ", true, tester.checkAuth());
}
Для кода, который не хорошо спроектирован (и не может быть протестирован), может потребоваться использовать еще один инструмент. В Java + Mockito вы можете использовать [PowerMock] (https: // github.ком/jayway/powermock). Это позволяет вам высмеивать конструкторы и другие вещи, к которым обычно не имеют доступа. Просто для того, чтобы объяснить себя по-другому, PowerMock - это сложный инструмент, который должен использоваться только для устаревших проектов (или областей проектов), которые ** не находятся под активным обслуживанием. Причина в том, что это сложная задача и делает тест довольно сложным читать. Если можно, попробуйте реорганизовать 'UserRole', чтобы его можно было протестировать. – Augusto
красивый комментарий для модульного тестирования n00bs, как я. Спасибо. – patateskafa
np! Я стараюсь избегать использования powermock в качестве чумы, поскольку я знаю, что это скользкий склон вниз к плохому дизайну, и для этого требуется время, чтобы оправиться от этого. Надеюсь, вы сможете пересмотреть проект, над которым вы работаете :). – Augusto