|
|
Re: unit test [message #757087 is a reply to message #756883] |
Wed, 16 November 2011 12:58 |
Andi Bur Messages: 5 Registered: March 2010 |
Junior Member |
|
|
Scout 3.7-SR1 contains the latest improvements of Scout testing.
At BSI, we create a test fragment for each application plug-in. The fragments contain the very same package structure as their host bundles. This makes it clear where to add a new test for a particular application class. Using fragments also allows accessing package private members of the class under test.
JUnit tests not requiring a running OSGi environment are straight forward. Those dealing with Scout objects (e.g. services, forms, outlines and desktop) have to run within a valid Scout context. Tests executed with a ScoutClientTestRunner or a ScoutServerTestRunner are running within such a context. Both runners can be configured with the @ClientTest and @ServerTest annotations, respectively.
Example:
@RunWith(ScoutClientTestRunner.class)
public class ExampleFormTest {
private ExampleForm m_form;
@Before
public void startUpForm() throws Exception {
m_form = new ExampleForm();
}
@After
public void closeForm() throws Exception {
if (m_form != null) {
m_form.doReset();
m_form.doCancel();
}
m_form = null;
}
@Test
public void testInit() throws Exception {
m_form.startNew();
assertEquals("content of UserField is not the current user",
ClientSession.get().getUserNr(), m_form.getUserField().getValue());
}
}
The test must be executed in a running OSGi environment. Unfortunately Eclipse's JUnit Plug-in test launcher does not work for Scout applications because all target platform and workspace Plug-ins are available in the test environment. A typical Scout application however runs in two different processes, one with all server resources and the other with all client bundles. Having all bundles available in one process would mix up services and service proxies. Therefore two additional product configurations are required.
The additional product configurations should be added to additional test plug-ins. First because Eclipse cannot cope with product extensions in fragment .xml files and second, because there is also an application required that drives the JUnit test execution. Scout provides a default application for this purpose, the ScoutJUnitPluginTestApplication. It is however very likely that there is additional setup required (e.g. registering mock services, authentication, default user...).
This is an extended example test application for scout clients:
public class ExampleClientTestApplication implements IApplication {
@Override
public Object start(IApplicationContext context) throws Exception {
intallNetAuthenticator();
installCookieStore();
ScoutClientTestRunner.setDefaultClientSessionClass(ClientSession.class);
return new ScoutJUnitPluginTestExecutor().runAllTests();
}
/**
* Installs an authenticator that is aware of different client sessions connecting concurrently to the same URL. The
* authenticator is registered as an OSGi service and used by Scout's network support which is based on Eclipse's
* networking features.
*
* @return Returns the authenticator's OSGi service registration.
*/
private Object intallNetAuthenticator() {
BundleContext bundleContext = Activator.getDefault().getBundle().getBundleContext();
ServiceRegistration reg = null;
Hashtable<String, Object> map = new Hashtable<String, Object>();
map.put(Constants.SERVICE_RANKING, 1);
// add credentials of test users
MultiClientAuthenticator.addUser("admin", "admin");
MultiClientAuthenticator.addUser("standard", "standard");
MultiClientAuthenticator.setDefaultUser("admin");
reg = bundleContext.registerService(java.net.Authenticator.class.getName(), new MultiClientAuthenticator(), map);
// start the netBundle, it is not started from OSGI because no references exists
Bundle netBundle = Platform.getBundle("org.eclipse.scout.net");
if (netBundle != null) {
try {
netBundle.start();
}
catch (Throwable t) {
netBundle = null;
}
}
return reg;
}
/**
* Installs a cookie store that is aware of different client sessions connecting concurrently to the same URL.
*/
private void installCookieStore() {
CookieManager.setDefault(new CookieManager(new MultiClientSessionCookieStore(), CookiePolicy.ACCEPT_ALL));
}
@Override
public void stop() {
}
}
And the corresponding test application for the server part:
public class BsiCrmServerTestApplication implements IApplication {
private static final String PERFORM_TESTS_AND_EXIT_ARG_NAME = "performTestsAndExit";
@Override
public Object start(IApplicationContext context) throws Exception {
// add here additional initialization
if (isExecuteServerSideTests()) {
ScoutServerTestRunner.setDefaultServerSessionClass(ServerSession.class);
ScoutServerTestRunner.setDefaultPrincipalName("admin");
new JUnitServerJob().schedule();
}
return IApplication.EXIT_OK;
}
@Override
public void stop() {
}
private boolean isExecuteServerSideTests() {
return TypeCastUtility.castValue(getConfigParameter(PERFORM_TESTS_AND_EXIT_ARG_NAME), boolean.class);
}
/**
* Returns the configuration value for the given parameter that is either configured as
* command line argument or as system property.
*
* @param parameterName
* @return
*/
private String getConfigParameter(String parameterName) {
String commandLineArgumentName = "-" + parameterName + "=";
for (String arg : Platform.getCommandLineArgs()) {
if (arg != null && arg.startsWith(commandLineArgumentName)) {
return arg.substring(commandLineArgumentName.length());
}
}
return System.getProperty(parameterName);
}
}
Starting the server product with the command line switch -performTestsAndExit=true executes all tests and stops the server afterwards; setting it to false starts the server so that it could be used by the client test product. Of course, it would be nice to test the client part without starting its server at all. This can be achieved by mocking all server service calls. Scout's testing support provides two methods in the TestingUtility for dynamically registering and unregistering services:
@BeforeClass
public static void beforeClass() throws Exception {
MockService service = new MockService();
dynamicServices=TestingUtility.registerServices(Activator.getDefault().getBundle().getBundleContext(), 1000, service);
}
@AfterClass
public static void afterClass() throws Exception {
TestingUtility.unregisterServices(dynamicServices);
}
We will provide a more extensive documentation in the wiki.
cheers
Andi
|
|
|
|
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03396 seconds