testing extensions

As I’m developing an extension, it would be nice if I could run it with a test so that I don’t have to load it into the Rhythmyx server over and over while I’m developing it.

Anyone have any pointers to the best way to write a test?

Right now, I am just trying out creating my own IPSAssemblyItem class, and just implementing the getters I need for testing. But I wonder if there is an easier way than doing this kind of thing?

April,

I’m a big fan of using JMock and JUnit. I write unit tests for most new extensions, and if you are only dealing the new “services”, there are interfaces for just about everything.

JMock does interfaces quite well. It’s possible to Mock a concrete class, but you can have trouble if the default constructor for that class makes calls to other objects. One of the big issues is the use of “Locators” (classes that extend PSBaseServiceLocator) in the constructors of objects. This basically makes them “untestable”.

In my own code, I try and isolate calls to any service locators into the “init” method of the class, and then I make sure that the unit test does not call the init method.

I also implement protected setter methods for all of the services, so that I can inject my mock services into the test method.

I hope this helps.

Dave

Thanks for the pointers. I use Junit, too. But I haven’t used JMock.

Looking at my question again, I realize that it sounds like I’m asking how to write tests in general. So just to clarify, I was asking specifically for pointers on writing tests for Rhythmyx Extensions.

And I thought my advice was oriented towards extensions.

While it’s possible to write tests on a running server (e.g. with Cactus and similar technologies), I think good unit tests are sufficient for most extensions.

Some of this depends on the type of extension being tested.

JEXL Expressions are the easiest, as they have no real dependencies on CMS objects (unless they call Java Services, in which case my previous advice about service locators applies)

For “pre-processing” and “post-processing” extensions require creation of a mock IPSRequestContext. This is easy to do with JMock. You’ll have to define the expectations so that they return appropriate objects.

In the case of post-processing extensions, you’ll probably need to create one or more “canned” XML documents for use in the test. I usually instantiate these with getClass().getResourceAsStream and the PSXmlDocumentBuilder class.

Let me know if you have specific questions I have not addressed.

Dave

It was. I was just clarifying in case anyone else chimes in.

[QUOTE=dbenua;10168]And I thought my advice was oriented towards extensions.

While it’s possible to write tests on a running server (e.g. with Cactus and similar technologies), I think good unit tests are sufficient for most extensions.

Some of this depends on the type of extension being tested.

JEXL Expressions are the easiest, as they have no real dependencies on CMS objects (unless they call Java Services, in which case my previous advice about service locators applies)

For “pre-processing” and “post-processing” extensions require creation of a mock IPSRequestContext. This is easy to do with JMock. You’ll have to define the expectations so that they return appropriate objects.

In the case of post-processing extensions, you’ll probably need to create one or more “canned” XML documents for use in the test. I usually instantiate these with getClass().getResourceAsStream and the PSXmlDocumentBuilder class.

Let me know if you have specific questions I have not addressed.

Dave[/QUOTE]

I’m wondering how hard it would be to set up a test environment that would use the spring beans to connect to a test database. Have you ever done anything like that? That way, I would have a real data repository to test my extension against.

Not sure if it would make sense to do that.

I did get pretty far using jmock. I managed to test a simple velocity extension enough to get it running without error, but I was unable to test if it actually did what it was supposed to, until I loaded it into the server.

It depends on what you depend on…

If all you want is data, you should be able to build a dummy Spring configuration and point to someplace. The path names are a little wierd. The best thing to do is call one of the locators and see what path Spring is looking for.

However, if you rely on the “Services” (e.g. the Assembly Service, the Content Manager, etc) then your best bet is to test in a running server. You can automate this with Cactus. Our developers use this method of some of their integration tests.

Cactus does require a fair amount of “setup” to get it running, and I’ve never found it to be worth it for extensions. Usually, I do behavioral unit tests that shake out the “stupid mistakes” in the new code, and then test in the server by hand to make sure that the server calls behave as I expect.

The behavioral unit tests also serve to guard against regressions, at least in part.

Thanks for the info.

I’m still trying to set up a dummy spring test environment. I’m stuck trying to get it to find the datasource. I put a copy of rx-ds.xml and the jtds.jar into the classpath when I run my test, but I still get the error

javax.naming.NameNotFoundException: Name [java:comp/env/jdbc/RhythmyxData] not bound; 0 bindings: []
at org.springframework.mock.jndi.SimpleNamingContext.lookup(SimpleNamingContext.java:134)

I’ve tested out the datasource definition (not to mention that it’s the same one that is used by my local installation of rhythmyx and it sems to work there)

How do I get my spring container to find the datasource?

Here is the bean definition that seems to be telling it where to look:


<bean class="com.percussion.services.datasource.PSDatasourceResolver" id="sys_datasourceResolver">
      <property name="repositoryDatasource" value="RhythmyxData"/>
      <property name="datasourceConfigurations">
         <list>
            <bean class="com.percussion.services.datasource.PSDatasourceConfig" id="RhythmyxData">
               <property name="name" value="RhythmyxData"/>
               <property name="dataSource" value="jdbc/RhythmyxData"/>
               <property name="database" value="aprildev"/>
               <property name="origin" value="dbo"/>
            </bean>
         </list>
      </property>
   </bean>

Thanks

If you want to run Spring standalone (without JBoss or a similar container) you cannot reference JNDI. You have to define the datasource directly in the Spring XML.

Look at Spring’s SimpleDriverDataSource (or DriverManagerDataSource).

[QUOTE=dbenua;10350]If you want to run Spring standalone (without JBoss or a similar container) you cannot reference JNDI. You have to define the datasource directly in the Spring XML.

Look at Spring’s SimpleDriverDataSource (or DriverManagerDataSource).[/QUOTE]

OK. I’ll try that. Thanks for the tip.

Your suggestion worked. I used DriverManagerDataSource and replaced the percussion session factory with LocalSessionFactoryBean.

But now I’m running into more JINDI and I’m not sure how to get around it:


 <bean class="org.springframework.jndi.JndiObjectFactoryBean" id="sys_jmsConnectionFactory">
		
      <property name="jndiName">
			
         <value>java:/ConnectionFactory</value>
		
      </property>
	
   </bean>

I’m wondering if I can somehow just tweezer this out, since I am not going to be testing messaging.

[QUOTE=dbenua;10350]If you want to run Spring standalone (without JBoss or a similar container) you cannot reference JNDI. You have to define the datasource directly in the Spring XML.

Look at Spring’s SimpleDriverDataSource (or DriverManagerDataSource).[/QUOTE]

In 6.6+, JMS Messaging is used for email notification and for publishing. If you don’t call those services, you might be able to just remove the references to the JMS connection factory from those 2 beans. I have not tried this, so I don’t know what will happen.

Dave

I simply commented out all the JMS beans, and I was able to load the spring services without error. I had to make sure that sybase.jar was in my run path, even though I’m using SQL Server.

[QUOTE=dbenua;10434]In 6.6+, JMS Messaging is used for email notification and for publishing. If you don’t call those services, you might be able to just remove the references to the JMS connection factory from those 2 beans. I have not tried this, so I don’t know what will happen.

Dave[/QUOTE]