/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
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 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
*/
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() {
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() {
List<Class<?>> classes = getTestClasses();
for (Class<?> 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() {
// loop over all methods in all test classes
for (Class<?> 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() {
// loop over all methods that _don't_ end in Test.class
for (Class<?> currentClass : getClasses("^.*(?<!Test|IT|PT)\\.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|IT|PT)\\.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<>();
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.lastIndexOf("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;
}
}