CND69UnitTestsPluginTutotial

Contents

Writing C/C++ Unit Tests Output Format Support Plugin

In NetBeans 6.9 was added support for unit tests in C/C++ projects.
This article describes how to extend this support via external plugins to support another tests output format.

See Adding Unit Tests to C/C++ Project to find out more information about C/C++ Unit Tests support in NetBeans.
See NetBeans Platform (RCP) and Module Development to find out more information about plugin development.

Creating new module

Plugin for NetBeans is a Netbeans module, so first of all let's create module.

image:nb69unittestsplugin_create_module.png

image:nb69unittestsplugin_create_module_name.png

image:nb69unittestsplugin_create_module_config.png

Adding libraries

We'll need folowing additional libraries:

  • Common Test Runner API
  • C/C++ Test Runner
  • Lookup

image:nb69unittestsplugin_libraries.png

Adding your module as a friend one

Common Test Runner API and C/C++ Test Runner are not public APIs.
So we'll have to make some hack to make our plugin work.

First will have to add our plugin as a friend to this module in our local version of NetBeans.
See Contributing to the NetBeans Code Base to find out how to get NetBeans sources, etc.

image:nb69unittestsplugin_common_testrunner_friend.png

image:nb69unittestsplugin_cnd_testrunner_friend.png

But this canges will allow you only to use your plugin in this local version of NetBeans.
To make it work in release version will make a real hack :)

Create module installer class.

image:nb69unittestsplugin_create_module_installer.png

Put following code inside:

package unit.test.output.handler;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.openide.modules.ModuleInstall;

/**
 * Hack to became a friend of C/C++ Tests Runner and Common Test Runner API
 *
 * @author Nikolay Krasilnikov (http://nnnnnk.name)
 */
public class Installer extends ModuleInstall {

    @Override
    public void installed() {
        initFriends();
        super.installed();
    }

    @Override
    public void restored() {
        initFriends();
        super.restored();
    }

    @Override
    public void validate() throws IllegalStateException {
        initFriends();
        super.validate();
    }

    private void initFriends() throws IllegalStateException {
        try {
            Class<?> main = Class.forName("org.netbeans.core.startup.Main", false, Thread.currentThread().getContextClassLoader());
            Method getModuleSystem = main.getMethod("getModuleSystem"); //NOI18N
            Object moduleSystem = getModuleSystem.invoke(null, new Object[0]);
            Method getManager = moduleSystem.getClass().getMethod("getManager"); //NOI18N
            Object moduleManager = getManager.invoke(moduleSystem, new Object[0]);
            Method moduleMeth = moduleManager.getClass().getMethod("get", String.class); //NOI18N
            // Let's became a friend of Common Tests Runner API
            Object persistence = moduleMeth.invoke(moduleManager, "org.netbeans.modules.gsf.testrunner"); //NOI18N
            if (persistence != null) {
                Field frField = persistence.getClass().getSuperclass().getDeclaredField("friendNames"); //NOI18N
                frField.setAccessible(true);
                @SuppressWarnings(value = "unchecked")
                Set<String> friends = (Set<String>) frField.get(persistence);
                if(friends == null) {
                    friends = new HashSet<String>();
                }
                friends.add("unit.test.output.handler"); //NOI18N
            }
            // Let's became a friend of C/C++ Tests Runner
            persistence = moduleMeth.invoke(moduleManager, "org.netbeans.modules.cnd.testrunner"); //NOI18N
            if (persistence != null) {
                Field frField = persistence.getClass().getSuperclass().getDeclaredField("friendNames"); //NOI18N
                frField.setAccessible(true);
                @SuppressWarnings(value = "unchecked")
                Set<String> friends = (Set<String>) frField.get(persistence);
                if(friends == null) {
                    friends = new HashSet<String>();
                }
                friends.add("unit.test.output.handler"); //NOI18N
            }
        } catch (Exception ex) {
            new IllegalStateException("Cannot fix dependencies for unit.test.output.handler.example.", ex); //NOI18N
        }
    }
}

This code adds your module as friend in runtime with help of reflections!

Implementing handlers

Now let's implement our output handlers.

We'd have to create handlers factory and factory provider.

Provider:

package unit.test.output.handler;

import org.netbeans.modules.cnd.testrunner.spi.TestHandlerFactory;
import org.netbeans.modules.cnd.testrunner.spi.TestHandlerFactoryProvider;

/**
 * Sample factory provider.
 *
 * @author Nikolay Krasilnikov (http://nnnnnk.name)
 */
@org.openide.util.lookup.ServiceProvider(service = org.netbeans.modules.cnd.testrunner.spi.TestHandlerFactoryProvider.class)
public class SampleTestHandlerFactoryProvider implements TestHandlerFactoryProvider {

    public TestHandlerFactory getFactory() {
        return new SampleTestHandlerFactory();
    }

}

Factory:

package unit.test.output.handler;

import java.util.ArrayList;
import java.util.List;
import org.netbeans.modules.cnd.testrunner.spi.TestHandlerFactory;
import org.netbeans.modules.cnd.testrunner.spi.TestRecognizerHandler;
import org.netbeans.modules.gsf.testrunner.api.Manager;
import org.netbeans.modules.gsf.testrunner.api.TestSession;
import org.netbeans.modules.gsf.testrunner.api.TestSuite;
import org.netbeans.modules.gsf.testrunner.api.Testcase;
import org.netbeans.modules.gsf.testrunner.api.Trouble;

/**
 * Sample factory.
 *
 * @author Nikolay Krasilnikov (http://nnnnnk.name)
 */
public class SampleTestHandlerFactory implements TestHandlerFactory {

    private static String C_UNIT = "C Unit Test"; // NOI18N

    public List<TestRecognizerHandler> createHandlers() {
        List<TestRecognizerHandler> result = new ArrayList<TestRecognizerHandler>();

        // CUnit
        result.add(new CUnitSuiteStartingHandler());
        result.add(new CUnitSuiteFinishedHandler());
        result.add(new CUnitTestFinishedHandler());
        result.add(new CUnitTestFailedHandler());

        return result;
    }

    public boolean printSummary() {
        return true;
    }

    static class CUnitSuiteStartingHandler extends TestRecognizerHandler {

        private boolean firstSuite = true;

        public CUnitSuiteStartingHandler() {
            super("Suite: (.+)"); //NOI18N
        }

        @Override
        public void updateUI(Manager manager, TestSession session) {
            if (firstSuite) {
                firstSuite = false;
                manager.testStarted(session);
            }
            String suiteName = matcher.group(1);
            session.addSuite(new TestSuite(suiteName));
            manager.displaySuiteRunning(session, suiteName);
        }
    }

    static class CUnitTestFinishedHandler extends TestRecognizerHandler {

        public CUnitTestFinishedHandler() {
            super("Test: (.*) \\.\\.\\. passed"); //NOI18N
        }

        @Override
        public void updateUI(Manager manager, TestSession session) {
            Testcase testcase = new Testcase(matcher.group(1), C_UNIT, session);
            testcase.setTimeMillis(0);
            testcase.setClassName(session.getCurrentSuite().getName());
            session.addTestCase(testcase);
        }
    }

    static class CUnitTestFailedHandler extends TestRecognizerHandler {

        public CUnitTestFailedHandler() {
            super("Test: (.*) \\.\\.\\. FAILED"); //NOI18N
        }

        @Override
        public void updateUI(Manager manager, TestSession session) {
            Testcase testcase = new Testcase(matcher.group(1), C_UNIT, session);
            testcase.setTimeMillis(0);
            testcase.setClassName(session.getCurrentSuite().getName());

            testcase.setTrouble(new Trouble(true));

            session.addTestCase(testcase);
        }
    }

    static class CUnitSuiteFinishedHandler extends TestRecognizerHandler {

        public CUnitSuiteFinishedHandler() {
            super("--Run Summary: "); //NOI18N
        }

        @Override
        public void updateUI(Manager manager, TestSession session) {
            manager.displayReport(session, session.getReport(0));
            manager.sessionFinished(session);
        }
    }
}

This handlers provides CUnit tests out put support.
There is no tutorial for Common Test Runer API, so try to implement your handlers in the same manner.

Creating NBM

Now compile and generate .nbm file - plugin binary.

image:nb69unittestsplugin_create_nbm.png

That's All!

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo