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

com.thesett.junit.extensions.AsymptoticTestCase Maven / Gradle / Ivy

Go to download

JUnit Toolkit enhances JUnit with performance testing, asymptotic behaviour analysis, and concurrency testing.

There is a newer version: 0.9.52
Show newest version
/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.thesett.junit.extensions;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import junit.framework.TestCase;

/**
 * AsymptoticTestCase is an extension of TestCase for writing unit tests to analyze asymptotic time and space behaviour.
 *
 * 

ParameterizedTestCases allow tests to be defined which have test methods that take a single int argument. Normal * JUnit test methods do not take any arguments. This int argument can be interpreted in any way by the test but it is * intended to denote the 'size' of the test to be run. For example, when testing the performance of a data structure * for different numbers of data elements held in the data structure the int parameter should be interpreted as the * number of elements. Test timings for different numbers of elements can then be captured and the asymptotic behaviour * of the data structure with respect to time analyzed. Any non-parameterized tests defined in extensions of this class * will also be run. * *

TestCases derived from this class may also define tear down methods to clean up their memory usage. This is * intended to be used in conjunction with memory listeners that report the amount of memory a test uses. The idea is to * write a test that allocates memory in the main test method in such a way that it leaves that memory still allocated * at the end of the test. The amount of memory used can then be measured before calling the tear down method to clean * it up. In the data structure example above, a test will allocate as many elements as are requested by the int * parameter and deallocate them in the tear down method. In this way memory readings for different numbers of elements * can be captured and the asymptotic behaviour of the data structure with respect to space analyzed. * *

*
CRC Card
Responsibilities Collaborations *
Store the current int parameter value. {@link TKTestResult} and see {@link AsymptoticTestDecorator} too. *
Invoke parameterized test methods. *
* * @author Rupert Smith * @todo If possible try to move the code that invokes the test and setup/teardown methods into {@link TKTestResult} * or {@link AsymptoticTestDecorator} rather than this class. This would mean that tests don't have to extend * this class to do time and space performance analysis, these methods could be added to any JUnit TestCase * class instead. This would be an improvement because existing unit tests wouldn't have to extend a different * class to work with this extension, and also tests that extend other junit extension classes could have * parameterized and tear down methods too. */ public class AsymptoticTestCase extends TestCase implements InstrumentedTest { /** Used for logging. */ /*private static final Logger log = Logger.getLogger(AsymptoticTestCase.class);*/ /** The name of the test case. */ private final String testCaseName; /** Thread local for holding measurements on a per thread basis. */ final ThreadLocal threadLocalMeasurement = new ThreadLocal() { /** * Sets up a default set test measurements (zeroed, apart from the size param which defaults to 1). * * @return A set of default test measurements. */ protected synchronized TestMeasurements initialValue() { return new TestMeasurements(); } }; /** * Constructs a test case with the given name. * * @param name The name of the test. */ public AsymptoticTestCase(String name) { super(name); /*log.debug("public AsymptoticTestCase(String " + name + "): called");*/ testCaseName = name; } /** * Gets the current value of the integer parameter to be passed to the parameterized test. * * @return The current value of the integer parameter. */ public int getN() { /*log.debug("public int getN(): called");*/ int n = threadLocalMeasurement.get().n; /*log.debug("return: " + n);*/ return n; } /** * Sets the current value of the integer parameter to be passed to the parameterized test. * * @param n The new current value of the integer parameter. */ public void setN(int n) { /*log.debug("public void setN(int " + n + "): called");*/ threadLocalMeasurement.get().n = n; } /** * Reports how long the test took to run. * * @return The time in milliseconds that the test took to run. */ public long getTestTime() { /*log.debug("public long getTestTime(): called");*/ long startTime = threadLocalMeasurement.get().startTime; long endTime = threadLocalMeasurement.get().endTime; long testTime = endTime - startTime; /*log.debug("return: " + testTime);*/ return testTime; } /** * Reports the memory usage at the start of the test. * * @return The memory usage at the start of the test. */ public long getTestStartMemory() { // log.debug("public long getTestStartMemory(): called"); long startMem = threadLocalMeasurement.get().startMem; // log.debug("return: " + startMem); return startMem; } /** * Reports the memory usage at the end of the test. * * @return The memory usage at the end of the test. */ public long getTestEndMemory() { // log.debug("public long getTestEndMemory(): called"); long endMem = threadLocalMeasurement.get().endMem; // log.debug("return: " + endMem); return endMem; } /** * Resets the instrumentation values to zero, and nulls any references to held measurements so that the memory can * be reclaimed. */ public void reset() { /*log.debug("public void reset(): called");*/ threadLocalMeasurement.remove(); } /** * Runs the test method for this test case. * * @throws Throwable Any Throwables from the test methods invoked are allowed to fall through. */ protected void runTest() throws Throwable { /*log.debug("protected void runTest(): called");*/ // Check that a test name has been set. This is used to define which method to run. assertNotNull(testCaseName); /*log.debug("testCaseName = " + testCaseName);*/ // Try to get the method with matching name. Method runMethod = null; boolean isParameterized = false; // Check if a parameterized test method is available. try { // Use getMethod to get all public inherited methods. getDeclaredMethods returns all // methods of this class but excludes the inherited ones. runMethod = getClass().getMethod(testCaseName, int.class); isParameterized = true; } catch (NoSuchMethodException e) { // log.debug("Parameterized method \"" + testCaseName + "\" not found."); // Set run method to null (it already will be but...) to indicate that no parameterized method // version could be found. Exception deliberately ignored as will now try to find non-parameterized method. e = null; runMethod = null; } // If no parameterized method is available, try and get the unparameterized method. if (runMethod == null) { try { runMethod = getClass().getMethod(testCaseName); isParameterized = false; } catch (NoSuchMethodException e) { // Exception deliberately ignored as it results in failing the test. e = null; fail("Method \"" + testCaseName + "\" not found."); } } // Check that the method is publicly accessable. if (!Modifier.isPublic(runMethod.getModifiers())) { fail("Method \"" + testCaseName + "\" should be public."); } // Try to execute the method, passing it the current int parameter value. Allow any invocation exceptions or // resulting exceptions from the method to fall through. try { Integer paramN = getN(); /*log.debug("paramN = " + paramN);*/ // Calculate parameters for parameterized tests so new does not get called during memory measurement. Object[] params = new Object[] { paramN }; // Take the test start memory and start time. threadLocalMeasurement.get().startMem = 0; // SizeOf.getUsedMemory(); threadLocalMeasurement.get().startTime = System.nanoTime(); if (isParameterized) { runMethod.invoke(this, params); } else { runMethod.invoke(this); } } catch (InvocationTargetException e) { e.fillInStackTrace(); throw e.getTargetException(); } catch (IllegalAccessException e) { e.fillInStackTrace(); throw e; } finally { // Take the test end memory and end time and calculate how long it took to run. long endTime = System.nanoTime(); threadLocalMeasurement.get().endTime = endTime; /*log.debug("startTime = " + threadLocalMeasurement.get().startTime + ", endTime = " + endTime + ", testTime = " + getTestTime());*/ threadLocalMeasurement.get().endMem = 0; // SizeOf.getUsedMemory(); } } /** * The test parameters, encapsulated as a unit for attaching on a per thread basis. */ private static class TestMeasurements { /** Holds the current value of the integer parameter to run tests on. */ public int n = 1; /** Holds the test start memory. */ public long startTime = 0; /** Holds the test end memory. */ public long endTime = 0; /** Holds the test start memory. */ public long startMem = 0; /** Holds the test end memory. */ public long endMem = 0; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy