Like Dan commented on the Unit Testing Struts 2.0 (Part 2) post, Struts 2.0 has changed it's API enough to make my previous code not work on latest version. So, in response to his comment, here is what I am using right now. Credit where it's due, the setup code is the one that The Arsenalist pointed out on his blog post Unit Testing Struts 2 Actions wired with Spring using JUnit. Again, credit where it's due...my thanks go to "The Arsenalist" for posting his solution.
/** * Class for easier support of Struts related * testing. Takes care of all the configuration details * that allow test classes to create beans (Spring), * actions (Struts), intercepted actions (Struts). * Class is singleton to minimize hit of initializing * Struts and related infrastructure (e.g. Hibernate). * * Adapted from code from "The Arsenalist" (http://arsenalist.com/), * see http://arsenalist.com/2007/06/18/unit-testing-struts-2-actions-spring-junit/ */ public class StrutsTestCaseSupport {
/** * Singleton access */ public static synchronized StrutsTestCaseSupport getInstance() throws Exception { if ( _theInstance == null ) { _theInstance = new StrutsTestCaseSupport(); } return _theInstance; }
/** * Class constructor, take care of Struts initializations */ private StrutsTestCaseSupport () throws Exception { String[] config = new String[] { "/WEB-INF/applicationContext.xml" };
// Link the servlet context and the Spring context servletContext = new MockServletContext(new FileSystemResourceLoader()); XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setServletContext(servletContext); appContext.setConfigLocations(config); appContext.refresh(); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appContext);
// Use spring as the object factory for Struts StrutsSpringObjectFactory ssf = new StrutsSpringObjectFactory(null, null, servletContext); ssf.setApplicationContext(appContext); StrutsSpringObjectFactory.setObjectFactory(ssf);
// Dispatcher is the guy that actually handles all requests. Pass in // an empty Map as the parameters but if you want to change stuff like // what config files to read, you need to specify them here // (see Dispatcher's source code) dispatcher = new Dispatcher(servletContext, new HashMap()); dispatcher.init(); Dispatcher.setInstance(dispatcher); }
/** * create a bean from the object factory (all wired up from Spring) * * @param beanName the name of the bean to get from the object factory * @param extraContent any extra content information to pass along to the bean building * process * @return the object factory created bean * @throws Exception on processing, configuration errors, test failure */ public Object createBean ( String beanName, Map
Like mentioned in previous postings, using this class is pretty straightforward, within your test you just do for beans:
Here we go again, it's that time of the year where good things are about to happen. September is marked by two major events: the release of Halo 3 ;-) and the return of the No Fluff Just Stuff conference (now called the New England Software Symposium). I have written about this even before but it does not hurt to repeat it...this is a really impressive conference and a must if you live around the Boston area. It takes place during a Friday afternoon and over the weekend. This is actually a great decision since it simplifies a lot the "need to be out of work" argument with your bosses. Sure it takes over your weekend but, if you're in this business you are most probably hooked enough to this stuff for this not to be a problem. The attendance to this event is capped at around 250 which is another great feature since it does allow you to be in those rooms listening to the presentations in a much close environment. You get to interact with the presenters both during the talks and during the breaks by mingling in lunch tables or just approaching them directly. The topics are amazing and, like I mentioned before (see here), the really annoying part of the even is choosing which sessions to go to. The price for the event is really a find...pretty affordable even if, like me, you do not get your company to sponsor you and pay out of your own pocket.
This fall, the Boston even takes place on the 14th (PM), 15th and 16th of September in Framingham, Massachusetts. For all the details, check out the event site.
I got my place already booked, what are you waiting for ?
In the hope that this adds to the list of solutions out there that can actually help people... If you are having keyboard mapping issues when trying to connect via vncviewer to a machine running vncserver on Ubuntu Feisty (7.04) with gnome, try this:
I have recently got the opportunity to get my hands on a copy of Vista Ultimate at MS employee prices. I jumped at the opportunity and, as soon as I ensured all my crucial apps actually ran on Vista (VMWare Workstation in particular), proceeded to install it on my laptop. I spend my working hours (and others for that matter) using this laptop so, although I surely did not get to explore all the niceties of Vista, I got the daily use experience of running it. The first impression was the "Wow" that MS advertises so much. It is indeed an eye-candy-filled OS. It looks awesome and all the UI interactions have been tuned to please the eye, Windows Aero is indeed really enticing. But...the niceties of a new UI only last so much...My daily work is spent mostly on another OS environment. All my work is done on Linux and I had been used to depend on VMWare Workstation to be able to get the best of both worlds and jump around as needed. My experience with XP and VMWare Workstation had been impeccable and I could not recommend it more...Then came Vista...oh well...Suddenly my Pentium 4 3.4Ghz with Hyperthreading, 2Gb RAM started grinding to a halt. Although a year old now, this is not (I believe) a run-of-the-mill laptop...A laptop with these specs should be able to handle this OS plus the apps that I needed to run on top of it! My frustration grew when looking at memory usage on Vista...Just starting up brought me to 600Mb usage, with VMWare I was up to 1.6Gb...this on a 2Gb RAM machine...And I started looking through the nice UI and thinking seriously that I could not work daily with this...The initial "Wow" turned into "Wow, this is unbearable!". So, after some serious consideration I decided it was time to byte the bullet and wipe out my system and replace it by something more snappy that actually made good use of my hardware...Ubuntu 7.04 to the rescue! Ok, I am not religious about the OS war and am one of the people who tries to take advantage of whatever each has to offer so, being the gamer that I am, I left Vista on a dual boot setup alongside Ubuntu (I still have hopes of playing Halo 2 on Vista someday to get my achievements! ). Now I am running Linux as a first OS...my life became a lot less stressing...and I can still run Windows XP or Win 2K on a VMWare Workstation virtual host for all the testing I need to do...The best of both worlds I would say...
With this Windows Vista we are bound to see a new need to get new hardware where once what you had was just fine...and, to be honest, without any real *day to day* real important enhancements that I can see (again, I stress the *day to day*... you might do cool and important things on Vista but I'm betting these are completely irrelevant for the common user).
But I believe Ubuntu 7.04 (and Linux in general) is still not there as well...I had to jump through some serious loops to get my Wireless card and my sound card to work on my laptop...It has evolved immensely no doubts. I still remember the old Linux installations of the early nineties where you really had to be courageous and curious to even try it. But good as it is this is hardly mass user ready...
In response to a comment made to Unit Testing Struts 2.0, here is the updated, complete code for Struts 2.0 testing. Hope this is useful. Have questions ? Want to discuss any of this ? Just drop me a line...Read on, includes support class code, small snippets for creation of Spring beans, Struts 2.0 actions, Struts 2.0 action proxies.
/** * Class for easier support of Struts related * testing. Takes care of all the configuration details * that allow test classes to create beans (Spring), * actions (Struts), intercepted actions (Struts). * Class is singleton to minimize hit of initializing * Struts and related infrastructure (e.g. Hibernate). * * @author Francisco Assis Rosa */ public class StrutsTestCaseSupport {
/** * Singleton variable */ public static StrutsTestCaseSupport _theInstance;
/** * Singleton access */ public static synchronized StrutsTestCaseSupport getInstance() { if ( _theInstance == null ) { _theInstance = new StrutsTestCaseSupport(); } return _theInstance; }
/** * Application context class (encapsulation of applicationContext.xml) */ ConfigurableWebApplicationContext _applicationContext;
/** * Configuration Manager object, to allow for encapusulation of struts.xml, * creation of actions and their proxied counterparts, creation of * servlet context from this application context */ ConfigurationManager _configurationManager;
/** * Class constructor, take care of Struts initializations */ private StrutsTestCaseSupport () {
// create the struts+spring integrated object factory // set spring autowiring by name for spring object factory Settings.set(StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE,"name"); StrutsSpringObjectFactory objectFactory = new StrutsSpringObjectFactory();
// set system object facory ObjectFactory.setObjectFactory(objectFactory);
// set action proxy factory ActionProxyFactory.setFactory(new StrutsActionProxyFactory());
// create a web application context instance (for spring configuration) _applicationContext = new XmlWebApplicationContext();
// get ahold of a servlet context to use in the creation of the application context ServletContext servletContext = createOneServletContext(_applicationContext); // complete application context initialization, pass in servlet // context and config file location, force reading of config (via refresh) _applicationContext.setServletContext(servletContext); _applicationContext.setConfigLocations(new String[] {"WEB-INF/applicationContext.xml"}); _applicationContext.refresh();
// initialize the object factory with the mock servlet context, application context objectFactory.init(servletContext); objectFactory.setApplicationContext(_applicationContext);
// add a default dispatcher to the system Dispatcher du = new Dispatcher(servletContext); Dispatcher.setInstance(du);
// pass over to the configuration manager location where struts-default.xml, // struts-plugin.xml and struts.xml can be found, force reading all _configurationManager = new ConfigurationManager(); _configurationManager.addConfigurationProvider( new StrutsXmlConfigurationProvider("struts-default.xml", false)); _configurationManager.addConfigurationProvider( new StrutsXmlConfigurationProvider("struts-plugin.xml", false)); _configurationManager.addConfigurationProvider( new StrutsXmlConfigurationProvider("struts.xml", false)); _configurationManager.reload(); }
/** * create a servlet context useable for a specific action * * @param applicationContext the application context to use in the servlet context * @return the created servlet context */ protected ServletContext createOneServletContext (ConfigurableWebApplicationContext applicationContext) { // create a servlet context for this action, use FileSystemResourceLoader for // context to find configuration files ServletContext servletContext = (ServletContext) new MockServletContext(new FileSystemResourceLoader());
// initialize freemarker manager config parameter to null (let FreemarkerManager figure // out configuration location out of ServletContext) Settings.set(StrutsConstants.STRUTS_I18N_ENCODING, "UTF-8"); servletContext.setAttribute(FreemarkerManager.CONFIG_SERVLET_CONTEXT_KEY,null);
// hand over application context to servlet context servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
return servletContext; }
/** * Build one action context for an accessmethod and an access url * * @param serverName the hostname that the request will need to hook up to * @param accessMethod http method to use (e.g. 'get', 'post', 'put', etc) * @param accessUrl the url to access * @return the map for the action's context * @throws Exception on processing, configuration errors, test failure */ public Map buildActionContext ( String serverName, String accessMethod, String accessUrl, Map requestParamMap ) throws Exception { // get ahold of a brand new servlet context ServletContext servletContext = createOneServletContext(_applicationContext);
// create fake request and response objects MockHttpServletRequest request = new MockHttpServletRequest(servletContext,accessMethod,accessUrl); MockHttpServletResponse response = new MockHttpServletResponse();
// set request server name request.setServerName(serverName);
// add context, request and response to an action context map Map actionContext = new HashMap(); actionContext.put(StrutsStatics.SERVLET_CONTEXT,servletContext); actionContext.put(StrutsStatics.HTTP_REQUEST,request); actionContext.put(StrutsStatics.HTTP_RESPONSE,response); actionContext.put(ActionContext.DEV_MODE,new Boolean(false)); // add request parameters to action context Map actionContextParams = new HashMap(); for ( String oneParamName : requestParamMap.keySet() ) { String[] paramValue = new String[1]; paramValue[0] = requestParamMap.get(oneParamName); actionContextParams.put(oneParamName,paramValue); } actionContext.put(ActionContext.PARAMETERS,actionContextParams);
return actionContext; }
/** * create a bean from the object factory (all wired up from Spring) * * @param beanName the name of the bean to get from the object factory * @param extraContent any extra content information to pass along to the bean building * process * @return the object factory created bean * @throws Exception on processing, configuration errors, test failure */ public Object createBean ( String beanName, Map extraContext ) throws Exception { return ObjectFactory.getObjectFactory().buildBean(beanName,extraContext); }
/** * create an action proxied by it's interceptor stack * * @param actionName the name/id for the action * @param actionNameSpace the namespace for the action * @param actionContext the action context for creating the proxy (created from buildActionContext) * @return the proxyed action * @throws Exception on processing, configuration errors, test failure */ public ActionProxy createActionProxy ( String actionName, String actionNamespace, Map actionContext) throws Exception { return createActionProxy(actionName,actionNamespace,actionContext,new HashMap()); }
/** * create an action proxied by it's interceptor stack * * @param actionName the name/id for the action * @param actionNameSpace the namespace for the action * @param actionContext the action context for creating the proxy (created from buildActionContext) * @param sessionMap the request/invocation session map (for http session map mocking) * @return the proxyed action * @throws Exception on processing, configuration errors, test failure */ public ActionProxy createActionProxy ( String actionName, String actionNamespace, Map actionContext, Map sessionMap ) throws Exception { ActionProxy actionProxy = ActionProxyFactory.getFactory().createActionProxy(_configurationManager.getConfiguration(),actionNamespace,actionName,actionContext);
// set the session map in the action proxy's invocation actionProxy.getInvocation().getInvocationContext().setSession(sessionMap);
return actionProxy; }
/** * create an action object, bypass all it's stacks. Have it properly injected * according to configurations. * * @param actionName the name/id for the action * @param actionNameSpace the namespace for the action * @param actionContext the action context for creating the proxy (created from buildActionContext) * @return the properly injected action * @throws Exception on processing, configuration errors, test failure */ public Object createAction ( String actionName, String actionNamespace, Map actionContext ) throws Exception { // get ahold of the action's configuration via the XWorkConfigRetriever class ActionConfig actionConfig = _configurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig(actionNamespace,actionName);
// create one instance of the action to test using the object factory, pass in action config and context return ObjectFactory.getObjectFactory().buildAction(actionName, actionNamespace, actionConfig, actionContext); }
Or to do a full fledged Struts 2.0 action proxy test:
// create action for ActionSearchTest Map requestParameters = new HashMap(); requestParameters.put("searchMode","quick"); requestParameters.put("searchText","Testing"); Map actionContext = StrutsTestCaseSupport.getInstance().buildActionContext("struts.assisrosa.com","get","/search/results",requestParameters);
// create the proxy for the action, this encapsulates all // the interception stack up to the real action ActionProxy proxy = StrutsTestCaseSupport.getInstance().createActionProxy("results","/search",actionContext);
// let the full stack run String result = proxy.execute();
// confirm result, any exception thrown will cause test to fail assert result.equals("success");
Or a Struts 2.0 action test (no proxy in front of it):
Continuous integration is a practice introduced by Extreme Programming (XP) that brings in the idea that developers should check in their code often and that their work should be continuously integrated and tested to ensure that no error goes unnoticed (see article by Martin Fowler). The practice is tightly integrated with the concepts of source control, unit testing and automated building as these are the privileged means of bringing the code together and running tests on it. Continuous integration (CI) not only works nicely but does enforces some pretty important habits to developers.
Developers working on a CI project will be required to use source control for their code. Sounds like a basic tool for any development project but I've seen too many projects where source control is completely absent...CI simply requires it...nice.
Developers working on a CI project will be rewarded by putting in place as many unit tests as possible. How ? By seeing that less errors will sneak by because of the existence of this safety net of testing. It is pretty cool to see that you avoid putting mistakes into production because of this first line of defense. Better our CI screaming at us than our clients right ?
Developers working on a CI project get used to the concept of automated building and the concept of building from scratch. Again, often have I seen in the past cases where code that is not rebuilt regularly from scratch becomes too entangled in dependencies that prevent it from building from a clean slate.
All these make for pretty strong points in favor of CI. And it is not that hard to put it in place...There is a significant amount of tools that joined together make for a great CI platform. Just look around. A winning combination for me, developing in Java, has been:
Cruise Control. A CI framework that glues together all the components to provide a pretty decent CI setup. From HTML reporting to email notification of success failures of builds, this is a pretty cool tool to use.
Subversion. A version control system that addresses a lot of the typical weak spots of other version control systems (e.g. CVS).
Ant. An automated build tool for Java. I doubt anyone working in Java never heard of Ant.
TestNG. A really cool testing framework for Java. Check it out...
All of the above are free tools that you can get and play with, together they make up for a pretty strong CI.
CI takes a step ahead when talking about Continuous Database Integration (CDBI). Paul Duvall at Test Early has been doing some pretty interesting presentations on it. It does bring a new level of testing to your database-driven apps. One which enforces the cooperation between developers and database administrators and builds a structure that ensures that you can deploy your application at any point in time. If you ever seen a project where to redeploy in a new system you have to go chasing for the DB schema required to deploy a clean system, you know the kind of sorrows CDBI can save you from.
I simply *guarantee you* that if you ever start using CI, you will not want to work again without it.
The title does sound presumptuous but after reading it you can only agree that if there is any Javascript book worth reading, this is it. David Flanagan does a most excellent work of introducing the Javascript language and of exploring all the kinks and nice features that you can take from it.
Having known Javascript for sometime I could not avoid being wowed in some chapters by some cool features that I really did not know existed in the language.
This 5th edition is well worth it even if you read previous editions. I did have a previous version and found that this new edition brings a significant amount of new content worth spending your budget in.
The book is well structure dividing it's presentation in core javascript and client-side javascript. Something I really liked seeing.
The core Javascript section presents pretty successfully crucial aspects of the language like closures and prototyping (among many others)...Even if you already know Javascript you should give it a try...I'm almost sure you will learn something from it.
The client-side Javascript is where this book gets even more of its value... from a fantastic CSS reference chapter (I do not believe you need much more than this to get you rolling with CSS), to even handling, DOM navigation, XML handling and scripting with Java, Flash, charting with Javascript and CSS (way cool). A really interesting read.
Like I said before, if you're out to get just one (or your first) Javascript book, I believe this is it! An interesting and absolutely essential read for any web developer these days.