I needed to run all my Groovy unit test cases using Junit ant task, but for whatever reason I was not able to do it. I was able to do it using the following:
Thursday, August 26, 2010
Wednesday, August 25, 2010
XML and Unit testing
I had to verify some XML using simple a String to verify. The code is the following:
When I ran the Junit task in Eclipse, everything was fine. But when I ran it in Junit Ant task, I got the following error:
Everything seems to be working fine. I'm not sure if the problem with the test was with the output of Ant. I believe that it might be something to do with the output of the console and the encoding that it uses, but either way XMLUnit seems to be a great candidate for testing any type of XML regardless of the format.
public class FetchMessageServiceTest {
...
private static final String XML_INCOMING = ""; secret password 8765 12345 0987654321 55225 testing 1,2
@Test
public void shouldReturnAnXml() throws SAXException, IOException {
FetchMessageService service = new FetchMessageService(jmsTemplate, incomingService);
assertNotNull(service);
Redirection redirectionMock = getRedirection();
String xml = service.getXml(redirectionMock);
assertNotNull(xml);
assertEquals(XML_INCOMING, xml);
}
When I ran the Junit task in Eclipse, everything was fine. But when I ran it in Junit Ant task, I got the following error:
[junit] expected:<<?xml version=["1.0" encoding="UTF-8"]?> [junit] <redirection><aut...> but was:<<?xml version=['1.0' encoding='UTF-8']?>
[junit] <redirection><aut...>
[junit] <redirection><aut...> but was:<<?xml version=['1.0' encoding='UTF-8']?>
[junit] <redirection><aut...>
I then decided to use XMLUnit. Once I end up doing this, everything worked perfect. I am not sure if it is something with the output of the Ant or if it's something with String. The code is the following:
@Test
public void shouldReturnAnXml() throws SAXException, IOException {
FetchMessageService service = new FetchMessageService(jmsTemplate, incomingService);
assertNotNull(service);
Redirection redirectionMock = getRedirection();
String xml = service.getXml(redirectionMock);
assertNotNull(xml);
XMLAssert.assertXMLEqual(XML_INCOMING, xml);
}
Everything seems to be working fine. I'm not sure if the problem with the test was with the output of Ant. I believe that it might be something to do with the output of the console and the encoding that it uses, but either way XMLUnit seems to be a great candidate for testing any type of XML regardless of the format.
Monday, August 23, 2010
Marshalling XML- Castor vs. Groovy MarkupBuilder
I worked on a small project where I needed to use some type of XML marshalling. I end up using Spring's (version 3) integration with Castor and JMS (ActiveMQ). I find it not that much flexible and eventually ended up using Groovy's XML libraries (really nice).
We had problems using the "conversion" of JMS (from object to JMS message), we find it easier to use an XML to transfer the messages in the JMS queue. The object that I wanted to convert to XML was a value object (immutable no setters) and using static factory. The object is the following:
The implementation of the Castor is pretty simple using Spring 3:
I used the mapping, since I needed to pass three objects to the static factory to create my Redirection object (Authentication, OperatorAndService, and Textmessage). The mapping file was the following:
public final class Redirection {
private RegisteredDate registeredDate;
private Authentication authentication;
private OperatorAndService operatorService;
private TextMessage textMessage;
private Redirection() {}
private Redirection(Authentication authentication,
OperatorAndService operatorService, TextMessage textMessage, Date date) {
this.authentication = authentication;
this.operatorService = operatorService;
this.textMessage = textMessage;
registeredDate = RegisteredDate.get( date!=null?date:new Date());
}
...
public static Redirection get(Authentication authentication,
OperatorAndService operatorService, TextMessage textMessage, Date date) {
return new Redirection(authentication, operatorService, textMessage, date);
}
...
public Authentication getAuthentication() {
return authentication;
}
public OperatorAndService getOperatorAndService() {
return operatorService;
}
public TextMessage getTextMessage() {
return textMessage;
}
public RegisteredDate getRegisteredDate() {
return registeredDate;
}
@Override
public String toString() {
return "Authentication: " + authentication + ", operator service: "
+ operatorService + ", text message: " + textMessage +
", registed date: " + registeredDate;
}
}
The implementation of the Castor is pretty simple using Spring 3:
I used the mapping, since I needed to pass three objects to the static factory to create my Redirection object (Authentication, OperatorAndService, and Textmessage). The mapping file was the following:
Mapping for the redirection object
The "get-method" is exactly what it means, is the method that you will use to fetch the object. The set-method is in case you have any setters (perfect for DTOs). However, my class is immutable so there are no setters. Instead, there is one static method that contains the three parameters that I needed to pass. There is a way to create an object without a constructor "verify-construcable=false". I wanted to see if there is a way to pass all the four object to my static factory, however, this did not work. The creation of the XML worked but not the creation of the object from the XML. I got the following error:
Castor unmarshalling exception; nested exception is org.exolab.castor.xml.MarshalException: unable to find matching public constructor for class
I try to look for a solution, but I had to tweak a lot of things to create a Redirection object. I then decided to look at Groovy's MarkupBuilder.
class XmlService {
private XmlService() {}
public static String getXml(Redirection redirect) {
if(redirect == null) {
throw new IllegalArgumentException("Redirection is invalid or null")
}
Authentication credentials = redirect.getAuthentication()
OperatorAndService operAndServ = redirect.getOperatorAndService()
TextMessage sms = redirect.getTextMessage()
def xml = new groovy.xml.StreamingMarkupBuilder()
xml.encoding = "UTF-8"
def redirection = {
mkp.xmlDeclaration()
redirection() {
authentication() {
username(credentials.getUsername())
password(credentials.getPassword())
}
operatorAndservice() {
serviceId(operAndServ.getServiceId())
operatorId(operAndServ.getOperatorId())
}
textmessage(){
phone(sms.getPhone())
shortcode(sms.getShortcode())
message(sms.getMessage())
}
registerdate(date:redirect.getRegisteredDate())
}
}
return xml.bind(redirection);
}
public static Redirection toRedirection(String xml) {
if(Validation.isEmpty(xml)) {
throw new IllegalArgumentException("The application needs to have an xml")
}
def redirectionXml = new XmlParser().parseText(xml)
//Authentication
String username = redirectionXml.authentication.username.text()
String password = redirectionXml.authentication.password.text()
def authentication = Authentication.get(username, password)
//Operator and service
String serviceId = redirectionXml.operatorAndservice.serviceId.text()
String operatorId = redirectionXml.operatorAndservice.operatorId.text()
def operatorAndService = OperatorAndService.get(operatorId, serviceId)
//Text message
String phone = redirectionXml.textmessage.phone.text()
String shortcode = redirectionXml.textmessage.shortcode.text()
String message = redirectionXml.textmessage.message.text()
def textMessage = TextMessage.get(phone, shortcode, message)
String registerDate = redirectionXml.registerdate[0].'@date'
def registeredDate = RegisteredDate.get(registerDate)
return Redirection.get(authentication,
operatorAndService, textMessage,
registeredDate.getRegisteredDate());
}
}
Groovy is a better candidate for this application. Its simplicity and flexibility beats Castor. The only thing that concerned me is the performance. I did noticed that the test cases using Castor were much faster. In case that performance is an issue, consider using Castor or other type of XML marshaling. I heard from one of my coworkers that xstream is very fast.
Subscribe to:
Posts (Atom)