Перейти к содержимому

Фотография

Выделение общего кода в отдельные классы


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 5

#1 Azur

Azur

    Новый участник

  • Members
  • Pip
  • 54 сообщений
  • ФИО:Александр Згнетов
  • Город:Омск

Отправлено 14 августа 2012 - 04:32

Добрый день. Хочу вынести повторяющиеся куски кода тестов (Java, JUnit4) в отдельные файлы (классы), есть сложности.

Во-первых, как я понял есть 2 способа это сделать, через наследование от другого класса и через использование метода другого класса без наследования. Мне больше нравится второй, хотя я пробовал оба варианта.

Пример общего класса
package common;

import org.openqa.selenium.*;

public class ComTest {
	public WebDriver driver;

	public void test1() throws Exception {
		driver.get("http://yandex.ru");
	}
}

Пример тестового класса
package registration;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

import common.ComTest;

public class Registration {
	public WebDriver driver;
	private String baseUrl;
	private StringBuffer verificationErrors = new StringBuffer();
	
	@Before
	public void setUp() throws Exception {
		System.setProperty("webdriver.firefox.profile", "selen");
		driver = new FirefoxDriver();
		baseUrl = "http://yandex.ru";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}
	
	@Test
	public void register() throws Exception {
		ComTest reg = new ComTest();
		reg.test1();
	}
}

В обоих случаях получаю ошибку java.lang.NullPointerException, ссылающуюся на driver.get общего класса, как я понимаю из-за обращения к неопределенному объекту. Если в общем классе объявить вебдрайвер как public WebDriver driver = new FirefoxDriver() то ошибка исчезает, но вебдрайвер запускается во втором окне браузера, которое не закрывается. Такое впечатление что @Before и @After из тестового класса не работают. А мне как раз и нужно, чтобы они использовались из тестового класса, а из общего только отдельные методы (функции).

Я не знаю как такую задачу реализуют по-уму, хотелось бы глянуть примеры.
  • 0

#2 Alex

Alex

    Постоянный участник

  • Members
  • PipPipPip
  • 237 сообщений
  • ФИО:Алексей

Отправлено 14 августа 2012 - 05:39

Добрый день. Хочу вынести повторяющиеся куски кода тестов (Java, JUnit4) в отдельные файлы (классы), есть сложности.

Во-первых, как я понял есть 2 способа это сделать, через наследование от другого класса и через использование метода другого класса без наследования. Мне больше нравится второй, хотя я пробовал оба варианта.

Пример общего класса

package common;

import org.openqa.selenium.*;

public class ComTest {
	public WebDriver driver;

	public void test1() throws Exception {
		driver.get("http://yandex.ru");
	}
}

Пример тестового класса
package registration;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

import common.ComTest;

public class Registration {
	public WebDriver driver;
	private String baseUrl;
	private StringBuffer verificationErrors = new StringBuffer();
	
	@Before
	public void setUp() throws Exception {
		System.setProperty("webdriver.firefox.profile", "selen");
		driver = new FirefoxDriver();
		baseUrl = "http://yandex.ru";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}
	
	@Test
	public void register() throws Exception {
		ComTest reg = new ComTest();
		reg.test1();
	}
}

В обоих случаях получаю ошибку java.lang.NullPointerException, ссылающуюся на driver.get общего класса, как я понимаю из-за обращения к неопределенному объекту. Если в общем классе объявить вебдрайвер как public WebDriver driver = new FirefoxDriver() то ошибка исчезает, но вебдрайвер запускается во втором окне браузера, которое не закрывается. Такое впечатление что @Before и @After из тестового класса не работают. А мне как раз и нужно, чтобы они использовались из тестового класса, а из общего только отдельные методы (функции).

Я не знаю как такую задачу реализуют по-уму, хотелось бы глянуть примеры.


Решить проблему можно двумя способами:

1) в конструктор класса ComTest добавить аргумент драйвера;
2) класс ComTest должен наследоваться от Registration. Это считается классическим подходом, если говорить о тестах: все тесты наследованы от одного или нескольких суперклассов, предоставлющих как раз таки методы before и after, связанный с инициализацией и закрытием драйвера (+ инициализация окружения и корректное завершение выполнения).

Для первого случая код изменится так:


package common;

import org.openqa.selenium.*;

public class ComTest {
	public final WebDriver driver;

	public ComTest(WebDriver driver){
	      this.driver = driver;
	}

	public void test1() throws Exception {
		driver.get("http://yandex.ru");
	}
}

package registration;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

import common.ComTest;

public class Registration {
	public WebDriver driver;
	private String baseUrl;
	private StringBuffer verificationErrors = new StringBuffer();
	
	@Before
	public void setUp() throws Exception {
		System.setProperty("webdriver.firefox.profile", "selen");
		driver = new FirefoxDriver();
		baseUrl = "http://yandex.ru";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}
	
	@Test
	public void register() throws Exception {
		ComTest reg = new ComTest(driver);
		reg.test1();
	}
}


Для второго случая:

package common;

import org.openqa.selenium.*;

public class ComTest extends Registration  {

        @Test
	public void test1() throws Exception {
		driver.get("http://yandex.ru");
	}
}

package registration;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

import common.ComTest;

public class Registration {
	public WebDriver driver;
	private String baseUrl;
	private StringBuffer verificationErrors = new StringBuffer();
	
	@Before
	public void setUp() throws Exception {
		System.setProperty("webdriver.firefox.profile", "selen");
		driver = new FirefoxDriver();
		baseUrl = "http://yandex.ru";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}
	
}


Обратите внимание, что во втором случае аннотация @Test и сам тестовый метод полностью переехали в ваш тест ComTest
  • 0

#3 Azur

Azur

    Новый участник

  • Members
  • Pip
  • 54 сообщений
  • ФИО:Александр Згнетов
  • Город:Омск

Отправлено 14 августа 2012 - 08:58

Спасибо. Первый способ в целом понятен. По второму хочу уточнить, при таком подходе атомарность тестов достигается за счет описания общего окружения, констант и параметров в родительском классе, а в дочерних сами тестовые методы... но что делать если метод будет требовать разные входные/выходные условия? При первом подходе можно импортировать несколько общих классов, а во втором множественное наследование не получится. Выходит надо строить иерархию общих классов, где каждый частный случай реализуется наследованием?
  • 0

#4 Alex

Alex

    Постоянный участник

  • Members
  • PipPipPip
  • 237 сообщений
  • ФИО:Алексей

Отправлено 15 августа 2012 - 06:44

Спасибо. Первый способ в целом понятен. По второму хочу уточнить, при таком подходе атомарность тестов достигается за счет описания общего окружения, констант и параметров в родительском классе, а в дочерних сами тестовые методы... но что делать если метод будет требовать разные входные/выходные условия? При первом подходе можно импортировать несколько общих классов, а во втором множественное наследование не получится. Выходит надо строить иерархию общих классов, где каждый частный случай реализуется наследованием?


Не совсем понимаю, что значит разные входные/выходные условия в контексте теста. Но в целом вы написали верно. Если есть такая необходимость, то необходимо разрабатывать несколько суперклассов в зависимости от ситуации. Также для этого можно использовать разделение на группы, если используете TestNG (не знаю, есть ли такая возможность в JUnit).
  • 0

#5 yulia_st

yulia_st

    Новый участник

  • Members
  • Pip
  • 25 сообщений

Отправлено 14 мая 2014 - 07:56

можно ли вынести в отдельный класс методы setUp и tearDown отмеченные аннотациями @Before @After?

затем создать объект класса и вызывать его метод.

будет ли работать такая конструкция?

я вроде даже пыталась проделать такую реструктуризацию, но почему-то такая конструкция не работала. 


  • 0

#6 user12

user12

    Специалист

  • Members
  • PipPipPipPipPip
  • 897 сообщений
  • ФИО:Виктор
  • Город:Минск


Отправлено 14 мая 2014 - 13:33

можно ли вынести в отдельный класс методы setUp и tearDown отмеченные аннотациями @Before @After?

затем создать объект класса и вызывать его метод.

будет ли работать такая конструкция?

я вроде даже пыталась проделать такую реструктуризацию, но почему-то такая конструкция не работала. 

 

Нет смысла в JUnit4 использовать @Before и @After. Это уже давно устарело. У JUnit4 есть очень мощная вещь - Rule и класс TestWatcher

1. Сначала Вам надо создать отдельный класс, типо MyBestRule.

2. Унаследоваться от TestWatcher -- MyRule extends TestWatcher

3. Там есть методы (т.е. в классе TestWatcher) --starting(аналог @Before) , finished(аналог @after), также проверки на успешное или не успешное выполнение теста =>

надо в вашем классе MyBestRule переопределить данные методы(setUp и tearDown) т.е. примерно так:

 @Override
    protected void starting(Description description) {
        System.out.println("BEFORE - данные из вашего метода setUp ");

    }



 @Override    protected void finished(Description description) {
        System.out.println("AFTER - данные из вашего метода tearDown");

    }

4.  В классе где находятся ваши тесты (@Test) добавить одну строчку:

@Rule

    public MyBestRule myBestRule= new MyBestRule();
 
Вот и все

  • 0


Количество пользователей, читающих эту тему: 1

0 пользователей, 1 гостей, 0 анонимных