alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

JMeter example source code file (JUnitSampler.java)

This example JMeter source code file (JUnitSampler.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - JMeter tags/keywords

annotatedtestcase, annotation, assertionfailederror, class, class, invocationtargetexception, method, object, object, reflection, string, string, stringbuilder, testcase, throwable, throwable, util

The JMeter JUnitSampler.java source code

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.jmeter.protocol.java.sampler;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Enumeration;

import junit.framework.AssertionFailedError;
import junit.framework.Protectable;
import junit.framework.TestCase;
import junit.framework.TestFailure;
import junit.framework.TestResult;

import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test.None;

/**
 *
 * This is a basic implementation that runs a single test method of
 * a JUnit test case. The current implementation will use the string
 * constructor first. If the test class does not declare a string
 * constructor, the sampler will try empty constructor.
 */
public class JUnitSampler extends AbstractSampler implements ThreadListener {

    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final long serialVersionUID = 240L; // Remember to change this when the class changes ...

    //++ JMX file attributes - do not change
    private static final String CLASSNAME = "junitSampler.classname";
    private static final String CONSTRUCTORSTRING = "junitsampler.constructorstring";
    private static final String METHOD = "junitsampler.method";
    private static final String ERROR = "junitsampler.error";
    private static final String ERRORCODE = "junitsampler.error.code";
    private static final String FAILURE = "junitsampler.failure";
    private static final String FAILURECODE = "junitsampler.failure.code";
    private static final String SUCCESS = "junitsampler.success";
    private static final String SUCCESSCODE = "junitsampler.success.code";
    private static final String FILTER = "junitsampler.pkg.filter";
    private static final String DOSETUP = "junitsampler.exec.setup";
    private static final String APPEND_ERROR = "junitsampler.append.error";
    private static final String APPEND_EXCEPTION = "junitsampler.append.exception";
    private static final String JUNIT4 = "junitsampler.junit4";
    //-- JMX file attributes - do not change

    private static final String SETUP = "setUp";
    private static final String TEARDOWN = "tearDown";

    // the Method objects for setUp (@Before) and tearDown (@After) methods
    // Will be null if not provided or not required
    private transient Method setUpMethod;
    private transient Method tearDownMethod;

    // The TestCase to run
    private transient TestCase testCase;
    // The test object, i.e. the instance of the class containing the test method
    // This is the same as testCase for JUnit3 tests
    // but different for JUnit4 tests which use a wrapper
    private transient Object testObject;

    // The method name to be invoked
    private transient String methodName;
    // The name of the class containing the method
    private transient String className;
    // The wrapper used to invoke the method
    private transient Protectable protectable;

    public JUnitSampler(){
    }

    /**
     * Method tries to get the setUp and tearDown method for the class
     * @param testObject
     */
    private void initMethodObjects(Object testObject){
        setUpMethod = null;
        tearDownMethod = null;
        if (!getDoNotSetUpTearDown()) {
            setUpMethod = getJunit4() ?
                getMethodWithAnnotation(testObject, Before.class)
                :
                getMethod(testObject, SETUP);
            tearDownMethod = getJunit4() ?
                getMethodWithAnnotation(testObject, After.class)
                :
                getMethod(testObject, TEARDOWN);
        }
    }

    /**
     * Sets the Classname attribute of the JavaConfig object
     *
     * @param classname
     *            the new Classname value
     */
    public void setClassname(String classname)
    {
        setProperty(CLASSNAME, classname);
    }

    /**
     * Gets the Classname attribute of the JavaConfig object
     *
     * @return  the Classname value
     */
    public String getClassname()
    {
        return getPropertyAsString(CLASSNAME);
    }

    /**
     * Set the string label used to create an instance of the
     * test with the string constructor.
     * @param constr
     */
    public void setConstructorString(String constr)
    {
        setProperty(CONSTRUCTORSTRING,constr);
    }

    /**
     * get the string passed to the string constructor
     */
    public String getConstructorString()
    {
        return getPropertyAsString(CONSTRUCTORSTRING);
    }

    /**
     * Return the name of the method to test
     */
    public String getMethod(){
        return getPropertyAsString(METHOD);
    }

    /**
     * Method should add the JUnit testXXX method to the list at
     * the end, since the sequence matters.
     * @param methodName
     */
    public void setMethod(String methodName){
        setProperty(METHOD,methodName);
    }

    /**
     * get the success message
     */
    public String getSuccess(){
        return getPropertyAsString(SUCCESS);
    }

    /**
     * set the success message
     * @param success
     */
    public void setSuccess(String success){
        setProperty(SUCCESS,success);
    }

    /**
     * get the success code defined by the user
     */
    public String getSuccessCode(){
        return getPropertyAsString(SUCCESSCODE);
    }

    /**
     * set the succes code. the success code should
     * be unique.
     * @param code
     */
    public void setSuccessCode(String code){
        setProperty(SUCCESSCODE,code);
    }

    /**
     * get the failure message
     */
    public String getFailure(){
        return getPropertyAsString(FAILURE);
    }

    /**
     * set the failure message
     * @param fail
     */
    public void setFailure(String fail){
        setProperty(FAILURE,fail);
    }

    /**
     * The failure code is used by other components
     */
    public String getFailureCode(){
        return getPropertyAsString(FAILURECODE);
    }

    /**
     * Provide some unique code to denote a type of failure
     * @param code
     */
    public void setFailureCode(String code){
        setProperty(FAILURECODE,code);
    }

    /**
     * return the descriptive error for the test
     */
    public String getError(){
        return getPropertyAsString(ERROR);
    }

    /**
     * provide a descriptive error for the test method. For
     * a description of the difference between failure and
     * error, please refer to the following url
     * http://junit.sourceforge.net/doc/faq/faq.htm#tests_9
     * @param error
     */
    public void setError(String error){
        setProperty(ERROR,error);
    }

    /**
     * return the error code for the test method. it should
     * be an unique error code.
     */
    public String getErrorCode(){
        return getPropertyAsString(ERRORCODE);
    }

    /**
     * provide an unique error code for when the test
     * does not pass the assert test.
     * @param code
     */
    public void setErrorCode(String code){
        setProperty(ERRORCODE,code);
    }

    /**
     * return the comma separated string for the filter
     */
    public String getFilterString(){
        return getPropertyAsString(FILTER);
    }

    /**
     * set the filter string in comman separated format
     * @param text
     */
    public void setFilterString(String text){
        setProperty(FILTER,text);
    }

    /**
     * if the sample shouldn't call setup/teardown, the
     * method returns true. It's meant for onetimesetup
     * and onetimeteardown.
     */
    public boolean getDoNotSetUpTearDown(){
        return getPropertyAsBoolean(DOSETUP);
    }

    /**
     * set the setup/teardown option
     * @param setup
     */
    public void setDoNotSetUpTearDown(boolean setup){
        setProperty(DOSETUP,String.valueOf(setup));
    }

    /**
     * If append error is not set, by default it is set to false,
     * which means users have to explicitly set the sampler to
     * append the assert errors. Because of how junit works, there
     * should only be one error
     */
    public boolean getAppendError() {
        return getPropertyAsBoolean(APPEND_ERROR,false);
    }

    /**
     * Set whether to append errors or not.
     *
     * @param error the setting to apply
     */
    public void setAppendError(boolean error) {
        setProperty(APPEND_ERROR,String.valueOf(error));
    }

    /**
     * If append exception is not set, by default it is set to false.
     * Users have to explicitly set it to true to see the exceptions
     * in the result tree.
     */
    public boolean getAppendException() {
        return getPropertyAsBoolean(APPEND_EXCEPTION,false);
    }

    /**
     * Set whether to append exceptions or not.
     *
     * @param exc the setting to apply.
     */
    public void setAppendException(boolean exc) {
        setProperty(APPEND_EXCEPTION,String.valueOf(exc));
    }

    /**
     * Check if JUnit4 (annotations) are to be used instead of
     * the JUnit3 style (TestClass and specific method names)
     *
     * @return true if JUnit4 (annotations) are to be used.
     * Default is false.
     */
    public boolean getJunit4() {
        return getPropertyAsBoolean(JUNIT4, false);
    }

    /**
     * Set whether to use JUnit4 style or not.
     * @param junit4 true if JUnit4 style is to be used.
     */
    public void setJunit4(boolean junit4) {
        setProperty(JUNIT4, junit4, false);
    }

    /** {@inheritDoc} */
    public SampleResult sample(Entry entry) {
        SampleResult sresult = new SampleResult();
        sresult.setSampleLabel(getName());// Bug 41522 - don't use rlabel here
        sresult.setSamplerData(className + "." + methodName);
        sresult.setDataType(SampleResult.TEXT);
        // Assume success
        sresult.setSuccessful(true);
        sresult.setResponseMessage(getSuccess());
        sresult.setResponseCode(getSuccessCode());
        if (this.testCase != null){
            // create a new TestResult
            TestResult tr = new TestResult();
            final TestCase theClazz = this.testCase;
            try {
                if (setUpMethod != null){
                    setUpMethod.invoke(this.testObject,new Object[0]);
                }
                sresult.sampleStart();
                tr.startTest(this.testCase);
                // Do not use TestCase.run(TestResult) method, since it will
                // call setUp and tearDown. Doing that will result in calling
                // the setUp and tearDown method twice and the elapsed time
                // will include setup and teardown.
                tr.runProtected(theClazz, protectable);
                tr.endTest(this.testCase);
                sresult.sampleEnd();
                if (tearDownMethod != null){
                    tearDownMethod.invoke(testObject,new Object[0]);
                }
            } catch (InvocationTargetException e) {
                Throwable cause = e.getCause();
                if (cause instanceof AssertionFailedError){
                    tr.addFailure(theClazz, (AssertionFailedError) cause);
                } else if (cause instanceof AssertionError) {
                    // Convert JUnit4 failure to Junit3 style
                    AssertionFailedError afe = new AssertionFailedError(cause.toString());
                    // copy the original stack trace
                    afe.setStackTrace(cause.getStackTrace());
                    tr.addFailure(theClazz, afe);
                } else if (cause != null) {
                    tr.addError(theClazz, cause);
                } else {
                    tr.addError(theClazz, e);
                }
            } catch (IllegalAccessException e) {
                tr.addError(theClazz, e);
            } catch (IllegalArgumentException e) {
                tr.addError(theClazz, e);
            }
            if ( !tr.wasSuccessful() ){
                sresult.setSuccessful(false);
                StringBuilder buf = new StringBuilder();
                StringBuilder buftrace = new StringBuilder();
                Enumeration<TestFailure> en;
                if (getAppendError()) {
                    en = tr.failures();
                    if (en.hasMoreElements()){
                        sresult.setResponseCode(getFailureCode());
                        buf.append( getFailure() );
                        buf.append("\n");
                    }
                    while (en.hasMoreElements()){
                        TestFailure item = en.nextElement();
                        buf.append( "Failure -- ");
                        buf.append( item.toString() );
                        buf.append("\n");
                        buftrace.append( "Failure -- ");
                        buftrace.append( item.toString() );
                        buftrace.append("\n");
                        buftrace.append( "Trace -- ");
                        buftrace.append( item.trace() );
                    }
                    en = tr.errors();
                    if (en.hasMoreElements()){
                        sresult.setResponseCode(getErrorCode());
                        buf.append( getError() );
                        buf.append("\n");
                    }
                    while (en.hasMoreElements()){
                        TestFailure item = en.nextElement();
                        buf.append( "Error -- ");
                        buf.append( item.toString() );
                        buf.append("\n");
                        buftrace.append( "Error -- ");
                        buftrace.append( item.toString() );
                        buftrace.append("\n");
                        buftrace.append( "Trace -- ");
                        buftrace.append( item.trace() );
                    }
                }
                sresult.setResponseMessage(buf.toString());
                sresult.setResponseData(buftrace.toString(), null);
            }
        } else {
            // we should log a warning, but allow the test to keep running
            sresult.setSuccessful(false);
            // this should be externalized to the properties
            sresult.setResponseMessage("failed to create an instance of the class");
            sresult.setResponseCode(getErrorCode());
        }
        return sresult;
    }

    /**
     * If the method is not able to create a new instance of the
     * class, it returns null and logs all the exceptions at
     * warning level.
     */
    private static Object getClassInstance(String className, String label){
        Object testclass = null;
        if (className != null){
            Constructor<?> con = null;
            Constructor<?> strCon = null;
            Class<?> theclazz = null;
            Object[] strParams = null;
            Object[] params = null;
            try
            {
                theclazz =
                    Thread.currentThread().getContextClassLoader().loadClass(className.trim());
            } catch (ClassNotFoundException e) {
                log.warn("ClassNotFoundException:: " + e.getMessage());
            }
            if (theclazz != null) {
                // first we see if the class declares a string
                // constructor. if it is doesn't we look for
                // empty constructor.
                try {
                    strCon = theclazz.getDeclaredConstructor(
                            new Class[] {String.class});
                    // we have to check and make sure the constructor is
                    // accessible. if we didn't it would throw an exception
                    // and cause a NPE.
                    if (label == null || label.length() == 0) {
                        label = className;
                    }
                    if (strCon.getModifiers() == Modifier.PUBLIC) {
                        strParams = new Object[]{label};
                    } else {
                        strCon = null;
                    }
                } catch (NoSuchMethodException e) {
                    log.info("String constructor:: " + e.getMessage());
                }
                try {
                    con = theclazz.getDeclaredConstructor(new Class[0]);
                    if (con != null){
                        params = new Object[]{};
                    }
                } catch (NoSuchMethodException e) {
                    log.info("Empty constructor:: " + e.getMessage());
                }
                try {
                    // if the string constructor is not null, we use it.
                    // if the string constructor is null, we use the empty
                    // constructor to get a new instance
                    if (strCon != null) {
                        testclass = strCon.newInstance(strParams);
                    } else if (con != null){
                        testclass = con.newInstance(params);
                    }
                } catch (InvocationTargetException e) {
                    log.warn(e.getMessage());
                } catch (InstantiationException e) {
                    log.info(e.getMessage());
                } catch (IllegalAccessException e) {
                    log.info(e.getMessage());
                }
            }
        }
        return testclass;
    }

    /**
     * Get a method.
     * @param clazz the classname (may be null)
     * @param method the method name (may be null)
     * @return the method or null if an error occurred
     * (or either parameter is null)
     */
    private Method getMethod(Object clazz, String method){
        if (clazz != null && method != null){
            try {
                return clazz.getClass().getMethod(method,new Class[0]);
            } catch (NoSuchMethodException e) {
                log.warn(e.getMessage());
            }
        }
        return null;
    }

    private Method getMethodWithAnnotation(Object clazz, Class<? extends Annotation> annotation) {
        if(null != clazz && null != annotation) {
            for(Method m : clazz.getClass().getMethods()) {
                if(m.isAnnotationPresent(annotation)) {
                    return m;
                }
            }
        }
        return null;
    }

    /*
     * Wrapper to convert a JUnit4 class into a TestCase
     *
     *  TODO - work out how to convert JUnit4 assertions so they are treated as failures rather than errors
     */
    private class AnnotatedTestCase extends TestCase {
        private final Method method;
        private final Class<? extends Throwable> expectedException;
        private final long timeout;
        public AnnotatedTestCase(Method method, Class<? extends Throwable> expectedException2, long timeout) {
            this.method = method;
            this.expectedException = expectedException2;
            this.timeout = timeout;
        }

        @Override
        protected void runTest() throws Throwable {
            try {
                long start = System.currentTimeMillis();
                method.invoke(testObject, (Object[])null);
                if (expectedException != None.class) {
                    throw new AssertionFailedError(
                    "No error was generated for a test case which specifies an error.");
                }
                if (timeout > 0){
                    long elapsed = System.currentTimeMillis() - start;
                    if (elapsed > timeout) {
                        throw new AssertionFailedError("Test took longer than the specified timeout.");
                    }
                }
            } catch (InvocationTargetException e) {
                Throwable thrown = e.getCause();
                if (thrown == null) { // probably should not happen
                    throw e;
                }
                if (expectedException == None.class){
                    // Convert JUnit4 AssertionError failures to JUnit3 style so
                    // will be treated as failure rather than error.
                    if (thrown instanceof AssertionError && !(thrown instanceof AssertionFailedError)){
                        AssertionFailedError afe = new AssertionFailedError(thrown.toString());
                        // copy the original stack trace
                        afe.setStackTrace(thrown.getStackTrace());
                        throw afe;
                    }
                    throw thrown;
                }
                if (!expectedException.isAssignableFrom(thrown.getClass())){
                    throw new AssertionFailedError("The wrong exception was thrown from the test case");
                }
            }
        }
    }

    public void threadFinished() {
    }

    /**
     * Set up all variables that don't change between samples.
     */
    public void threadStarted() {
        testObject = null;
        testCase = null;
        methodName = getMethod();
        className = getClassname();
        final Method m;
        protectable = null;
        String rlabel = getConstructorString();
        if (rlabel.length()== 0) {
            rlabel = JUnitSampler.class.getName();
        }
        this.testObject = getClassInstance(className,rlabel);
        if (this.testObject != null){
            initMethodObjects(this.testObject);
            m = getMethod(this.testObject,methodName);
            if (getJunit4()){
                Class<? extends Throwable> expectedException = None.class;
                long timeout = 0;
                Test annotation = m.getAnnotation(Test.class);
                if(null != annotation) {
                    expectedException = annotation.expected();
                    timeout = annotation.timeout();
                }
                final AnnotatedTestCase at = new AnnotatedTestCase(m, expectedException, timeout);
                testCase = at;
                protectable = new Protectable() {
                    public void protect() throws Throwable {
                        at.runTest();
                    }
                };
            } else {
                this.testCase = (TestCase) this.testObject;
                final Object theClazz = this.testObject; // Must be final to create instance
                protectable = new Protectable() {
                    public void protect() throws Throwable {
                        try {
                            m.invoke(theClazz,new Object[0]);
                        } catch (InvocationTargetException e) {
                            /*
                             * Calling a method via reflection results in wrapping any
                             * Exceptions in ITE; unwrap these here so runProtected can
                             * allocate them correctly.
                             */
                            Throwable t = e.getCause();
                            if (t != null) {
                                throw t;
                            }
                            throw e;
                        }
                    }
                };
            }
            if (this.testCase != null){
                this.testCase.setName(methodName);
            }
        }
    }
}

Other JMeter examples (source code examples)

Here is a short list of links related to this JMeter JUnitSampler.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.