All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.inftec.ju.ee.webtest.DriverRule Maven / Gradle / Ivy

Go to download

Contains helping classes for Unit Testing, supporting CDI and EE features, including DB access

There is a newer version: 4.5.1-11
Show newest version
package ch.inftec.ju.ee.webtest;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Assert;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.inftec.ju.testing.db.DbTestAnnotationHandler;
import ch.inftec.ju.testing.db.JuTestEnv;
import ch.inftec.ju.util.AssertUtil;
import ch.inftec.ju.util.JuRuntimeException;
import ch.inftec.ju.util.JuStringUtils;
import ch.inftec.ju.util.JuUrl;
import ch.inftec.ju.util.JuUtils;
import ch.inftec.ju.util.PropertyChain;
import ch.inftec.ju.util.ReflectUtils;
import ch.inftec.ju.util.ReflectUtils.AnnotationInfo;
import ch.inftec.ju.util.SystemPropertyTempSetter;
import ch.inftec.ju.util.TestUtils;

/**
 * JUnit rule to run web tests with (multiple) selenium drivers.
 * @author Martin
 *
 */
public class DriverRule implements TestRule {
	private static boolean copiedChromeDriverExe = false;
	
	private static final String PROP_DRIVER = "ju-testing-ee.selenium.driver";
	private static final String CHROME_DRIVER_EXE_PATH = "target/chromedriver.exe";
	
	private static final Logger logger = LoggerFactory.getLogger(DriverRule.class);
	
	private final WebTest testClass;
	
	// JUnit will create a new Rule instance for every test method run. Therefore, we'll use static references
	// to handle our drivers...
	private static List driverHandlers = new ArrayList<>();

	DriverRule(WebTest testClass) {
		this.testClass = testClass;
	}
	
	@Override
	public Statement apply(final Statement base, Description description) {
		// Handle JuTestEnv annotations
		Method method = TestUtils.getTestMethod(description);
		List> testEnvAnnos = ReflectUtils.getAnnotationsWithInfo(method, JuTestEnv.class, false, true, true);
		Collections.reverse(testEnvAnnos);
		final SystemPropertyTempSetter tempSetter = DbTestAnnotationHandler.setTestEnvProperties(testEnvAnnos);
		
		try {
			PropertyChain pc = JuUtils.getJuPropertyChain();
			
			if (DriverRule.driverHandlers.isEmpty()) {
				// Get from the properties which drivers we should use to run the tests 
				String drivers[] = JuStringUtils.split(pc.get(PROP_DRIVER, true), ",", true);
				Assert.assertTrue(String.format("No drivers specified in property %s", DriverRule.PROP_DRIVER), drivers.length > 0);
				
				logger.debug("Initialize WebDrivers: " + Arrays.toString(drivers));
				for (String driverType : drivers) {
					logger.debug("Creating driver: " + driverType);
					
					if ("HtmlUnit".equals(driverType)) {
						DriverRule.driverHandlers.add(new HtmlUnitDriverHandler());
					} else if ("Chrome".equals(driverType)) {
						DriverRule.driverHandlers.add(new ChromeDriverHandler());
					} else {
						throw new JuRuntimeException(String.format("Unsupported selenium driver type: %s. Check value of property %s"
								, driverType
								, PROP_DRIVER));
					}
				}
			}
			
			return new Statement() {
				public void evaluate() throws Throwable {
					try {
						// Run test case for with all drivers.
						// We cannot use a for-iterator here as the closeAll method gets called when the for
						// method tries to loop again, resulting in a ConcurrentModificationException.
						for (int i = 0; i < driverHandlers.size(); i++) {
							DriverHandler driverHandler = driverHandlers.get(0);
							try (DriverHandler.DriverHandlerCreator driverCreator = driverHandler.newDriverHandlerCreator()) {
								logger.info("Running test with WebDriver " + driverCreator);
								testClass.driver = driverCreator.getDriver();

								// If the evaluation fails, it will break our loop, i.e. if we want to run drivers
								// d1 and d2 and in d1, we have an exception, d2 won't be executed at all...
								base.evaluate();
							}
						}
					} finally {
						tempSetter.close();
					}
				}
			};
		} catch (Exception ex) {
			tempSetter.close();
			throw ex;
		}
	}
	
	/**
	 * Disposes all open resources a DriverRule may hold.
	 * 

* This should be called after the test class has been executed. */ public static void closeAll() { // Clear DriverHandlers. This way, we may specify drivers to use in a system property. driverHandlers.clear(); } private static abstract class DriverHandler { protected final PropertyChain pc = JuUtils.getJuPropertyChain(); public DriverHandlerCreator newDriverHandlerCreator() { return new DriverHandlerCreator(); } private class DriverHandlerCreator implements AutoCloseable { private final WebDriver driver; public DriverHandlerCreator() { this.driver = createWebDriver(); } public WebDriver getDriver() { return driver; } @Override public void close() throws Exception { logger.debug("Closing WebDriver " + this.toString()); this.driver.quit(); } @Override public String toString() { return String.format("%s [WebDriver: %s]", DriverHandler.this.getClass().getSimpleName(), this.driver); } } protected abstract WebDriver createWebDriver(); } public static class HtmlUnitDriverHandler extends DriverHandler { @Override protected WebDriver createWebDriver() { boolean enableJavaScript = pc.get("ju-testing-ee.selenium.htmlUnit.enableJavascript", Boolean.class); return new HtmlUnitDriver(enableJavaScript); } } public static class ChromeDriverHandler extends DriverHandler { @Override protected WebDriver createWebDriver() { System.setProperty("webdriver.chrome.driver", DriverRule.getChromeDriverExePath().toAbsolutePath().toString()); return new ChromeDriver(); } } private static Path getChromeDriverExePath() { // We'll store the chromedriver in the target directory of the current working folder Path chromeDriverExePath = Paths.get(DriverRule.CHROME_DRIVER_EXE_PATH); try { if (Files.notExists(chromeDriverExePath) || !DriverRule.copiedChromeDriverExe) { URL chromedriverResourceUrl = JuUrl.resource("chromedriver.exe"); AssertUtil.assertNotNull("Couldn't find chromedriver.exe on classpath", chromedriverResourceUrl); logger.debug("Copying chromedriver.exe from resource {} to {}" , chromedriverResourceUrl , chromeDriverExePath.toAbsolutePath()); try (InputStream is = new BufferedInputStream(chromedriverResourceUrl.openStream())) { Files.copy(is, chromeDriverExePath, StandardCopyOption.REPLACE_EXISTING); } DriverRule.copiedChromeDriverExe = true; } } catch (Exception ex) { throw new JuRuntimeException("Couldn't copy chromedriver.exe to " + chromeDriverExePath, ex); } return chromeDriverExePath; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy