CND69UnitTestsPluginTutotial
(Created page with '=Writing C/C++ Unit Tests Output Format Support Plugin= <p> In NetBeans 6.9 was added support for unit tests in C/C++ projects.<br> This article describes how to extend …')
Newer edit →
Revision as of 18:54, 19 April 2010
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.
Adding libraries
We'll need folowing additional libraries:
- Common Test Runner API
- C/C++ Test Runner
- Lookup
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.
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.
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.
That's All!