Сегодня я расскажу об использовании рефлексии языка при написании тестов.
CtClass cc = pool.getCtClass(classname); // получаем наш класс из пула
CtField[] fields=cc.getDeclaredFields(); // получаем список всех полей
ClassFile ccFile = cc.getClassFile(); // получаем сам класс-файл
ConstPool constpool = ccFile.getConstPool();
for(CtField f:fields){
if(props.containsKey(f.getName())){
Что это и для чего нужно ?
Рефлексия - процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения.
Это бывает необходимо если вы хотите создать достаточно гибкую систему тестов, которая будет легко подвергаться настройке и изменения без внесения изменений в код.
Пример
Предположим вы написали некий класс, описывающий веб-страницу с использованием Selenium PageFactory.
В ходе выполнения тестов выяснилось что местоположение и идентификаторы элементов за аннотированных как @FindBy могут часто меняться.
Как тогда быть ?
Постоянно переписывать все аннотации ?
Или вынести все аннотации по внешний файл с настройками и менять их там без перекомпиляции кода ?
Последний вариант на мой взгляд наиболее приемлем.
Реализация
Для реализации нашего варианта нам и потребуется рефлексия.
Будем использовать библиотеку Javassist.
Ее использование дает нам самые широкие возможности по изменению кода в рантайме. Вплоть до изменения аннотаций !!!
пусть у нас в некоем классе описан элемент:
@FindBy(how = How.ID, using = "element_id")
private WebElement element;
private WebElement element;
мы хотим в рантайме менять аттрибуты how и using у аннотации.
значения using будем подгружать из файла настроек.
Для этого напишем класс-адаптер:
public class InterfaceAdaptor {
public static Class adapt(String classname) {
Properties props=new Properties();
props.load(new FileInputStream(new File(classname+".props"))); //загружаем файл с настройками
ClassPool pool = ClassPool.getDefault(); // получаем пулл классов
Properties props=new Properties();
props.load(new FileInputStream(new File(classname+".props"))); //загружаем файл с настройками
ClassPool pool = ClassPool.getDefault(); // получаем пулл классов
CtClass cc = pool.getCtClass(classname); // получаем наш класс из пула
CtField[] fields=cc.getDeclaredFields(); // получаем список всех полей
ClassFile ccFile = cc.getClassFile(); // получаем сам класс-файл
ConstPool constpool = ccFile.getConstPool();
for(CtField f:fields){
if(props.containsKey(f.getName())){
// если в пропертис находим значение соответствующее имени поля
// устанавливаем для этого поля аннотацию с нужными нам параметрами
// устанавливаем для этого поля аннотацию с нужными нам параметрами
//новая аннотация перезаписывает старую
AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation("org.openqa.selenium.support.FindBy", constpool);
EnumMemberValue e=new EnumMemberValue(ccFile.getConstPool());
e.setType("org.openqa.selenium.support.How");
e.setValue("XPATH");
annot.addMemberValue("how",e );
annot.addMemberValue("using", new StringMemberValue(props.getProperty(f.getName()),ccFile.getConstPool()));
attr.addAnnotation(annot); //добавляем аннотация
f.getFieldInfo().addAttribute(attr); //добавляем аттрибуты
//
}
}
return cc.toClass(); // возвращаем новый исправленный класс
}
}
AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation("org.openqa.selenium.support.FindBy", constpool);
EnumMemberValue e=new EnumMemberValue(ccFile.getConstPool());
e.setType("org.openqa.selenium.support.How");
e.setValue("XPATH");
annot.addMemberValue("how",e );
annot.addMemberValue("using", new StringMemberValue(props.getProperty(f.getName()),ccFile.getConstPool()));
attr.addAnnotation(annot); //добавляем аннотация
f.getFieldInfo().addAttribute(attr); //добавляем аттрибуты
//
}
}
return cc.toClass(); // возвращаем новый исправленный класс
}
}
После того как мы получили класс мы можем опять таки через рефлексию получить его инстанс.
InterfaceAdaptor.adapt("org.your.ClassName").getConstructors()[0].newInstance();
Комментариев нет:
Отправить комментарий