/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs; import static org.junit.Assert.assertTrue; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import junit.framework.TestCase; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.openmrs.util.OpenmrsUtil; /** * Runs tests on the openmrs junit tests TODO: add unit test to make sure all tests have a call to * assert* in them. This would help prevent people from making tests that just print results to the * screen */ @SuppressWarnings("unchecked") public class OpenmrsTestsTest { private ClassLoader classLoader = this.getClass().getClassLoader(); private List<Class> testClasses = null; /** * Make sure there is at least one _other_ test case out there * * @throws Exception */ @Test public void shouldHaveAtLeastOneTest() throws Exception { List<Class> classes = getTestClasses(); assertTrue("There should be more than one class but there was only " + classes.size(), classes.size() > 1); } /** * Makes sure all test methods in org.openmrs start with the word "should" * * @throws Exception */ @Test public void shouldStartWithShould() throws Exception { List<Class> classes = getTestClasses(); for (Class<TestCase> currentClass : classes) { for (Method method : currentClass.getMethods()) { // make sure every "test" method (determined by having // the @Test annotation) starts with "testShould" if (method.getAnnotation(Test.class) != null) { String methodName = method.getName(); boolean passes = methodName.startsWith("should") || methodName.contains("_should"); assertTrue(currentClass.getName() + "#" + methodName + " is supposed to either 1) start with 'should' or 2) contain '_should' but it doesn't", passes); } } } } /** * Makes sure all "should___" methods in org.openmrs have an "@Test" annotation on it. This is * to help prevent devs from forgetting to put the annotation and then seeing all tests pass * because the new test wasn't actually ran * * @throws Exception */ @Test public void shouldHaveTestAnnotationWhenStartingWithShould() throws Exception { // loop over all methods in all test classes for (Class<TestCase> currentClass : getTestClasses()) { for (Method method : currentClass.getMethods()) { String methodName = method.getName(); // make sure every should___ method has an @Test annotation if (methodName.startsWith("should") || methodName.contains("_should")) { assertTrue(currentClass.getName() + "#" + methodName + " does not have the @Test annotation on it even though the method name starts with 'should'", method.getAnnotation(Test.class) != null); } } } } /** * Checks that a user hasn't accidentally created a test class that doesn't end with "Test". (If * it doesn't, it isn't picked up by the test aggregator Ant target: junit-report) <br/> * <br/> * This class looks at all classes in the org.openmrs package. If a class contains an "@Test" * annotated method but its class name does not end with Test, it fails. * * @throws Exception */ @Test public void shouldHaveClassNameEndWithTestIfContainsMethodTestAnnotations() throws Exception { // loop over all methods that _don't_ end in Test.class for (Class<?> currentClass : getClasses("^.*(?<!Test)\\.class$")) { // skip over classes that are @Ignore'd if (currentClass.getAnnotation(Ignore.class) == null) { boolean foundATestMethod = false; for (Method method : currentClass.getMethods()) { if (method.getAnnotation(Test.class) != null) { foundATestMethod = true; } } Assert.assertFalse( currentClass.getName() + " does not end with 'Test' but contains @Test annotated methods", foundATestMethod); } } } /** * Get all classes ending in "Test.class". * * @return list of classes whose name ends with Test.class */ private List<Class> getTestClasses() { return getClasses(".*Test\\.class$"); } /** * Get all classes in the org.openmrs.test package * * @return list of TestCase classes in org.openmrs.test */ private List<Class> getClasses(String classNameRegex) { if (testClasses != null) return testClasses; Pattern pattern = Pattern.compile(classNameRegex); URL url = classLoader.getResource("org/openmrs"); File directory = OpenmrsUtil.url2file(url); // make sure we get a directory back assertTrue("org.openmrs.test should be a directory", directory.isDirectory()); testClasses = getClassesInDirectory(directory, pattern); // check to see if the web layer is also included. Skip it if its not there url = classLoader.getResource("org/openmrs/web"); if (url != null) { directory = OpenmrsUtil.url2file(url); // make sure we get a directory back assertTrue("org.openmrs.web.test should be a directory", directory.isDirectory()); testClasses.addAll(getClassesInDirectory(directory, pattern)); } return testClasses; } /** * Recurses into the given directory checking that all test methods start with "testShould" * * @param directory to loop through the files of */ private List<Class> getClassesInDirectory(File directory, Pattern pattern) { List<Class> currentDirTestClasses = new ArrayList<Class>(); for (File currentFile : directory.listFiles()) { // if looking at a folder, recurse into it if (currentFile.isDirectory()) { currentDirTestClasses.addAll(getClassesInDirectory(currentFile, pattern)); } // if the user only wants classes ending in Test or they want all of them if (pattern.matcher(currentFile.getName()).matches()) { // strip off the extension String className = currentFile.getAbsolutePath().replace(".class", ""); // switch to dot separation className = className.replace(File.separator, "."); // strip out the beginning (/home/ben/workspace...) up to org.openmrs. className = className.substring(className.indexOf("org.openmrs.")); try { Class<?> currentClass = classLoader.loadClass(className); currentDirTestClasses.add(currentClass); } catch (ClassNotFoundException e) { System.out.println("Unable to load class: " + className + " error: " + e.getMessage()); } } } return currentDirTestClasses; } }