KakimotOnline

July 22, 2009

Singleton (Anti-) Pattern

Filed under: programming, refactoring, software design, testing — Tags: , , — nandokakimoto @ 3:51 am

I’ve implemented my first design patterns at college, while creating a web system during the software engineer course. My classmates and I needed a facade class with a single instance of it throughout the system. So, because we’re really smart, we’ve applied the Facade and Singleton pattern. Actually, we’ve implemented the patterns without knowledge of the design patterns catalog. For us, it was just a way to get what we need.

This week, while doing my daily work, I realized how dangerous the Singleton pattern is. Well, I would have noticed it before, if I have used Test-First Programming. Even knowing the benefits of TDD, I decided to write some code in advance, since I don’t have much experience on the platform used and on its supported tests framework.

My task was to create a GPS abstraction and use it in a mobile Navigator module. My first thought was making my GPS abstraction a Singleton class. It looked very obvious for me: a mobile device has only one GPS and different GPS intances will provide the same data set. So, what I need is just a single GPS instance troughout the system.

After some minutes writing code, I’ve created abstractions similar to the Java sample below.

GPSProvider.java

import java.util.List;

public class GPSProvider implements LBSPositionObserver {

 private static GPSProvider INSTANCE = new GPSProvider();
 private Position lastCoordinate;
 private List<GPSListener> listeners;

 private GPSProvider() {
 this.listeners = new ArrayList<GPSListener>();
 }

 //retrive the class instance
 public static GPSProvider GetInstance() {
 return INSTANCE;
 }

 // perform GPS initialization
 public void initGPSService() {
 (...)
 }

 // add a new listener to the gps class
 public void attach(GPSListener listener) {
 this.listeners.add(listener);
 }

 // remove a listener from the class list
 public void dettach(GPSListener listener) {
 this.listeners.remove(listener);
 }

 @Override
 // set lastCoordinate and notify all listeners about the update
 public void positionUpdated(Position position) {
 this.lastCoordinate = position;
 for ( GPSListener listener : this.listeners ) {
 listener.positionUpdated(position);
 }
 }

 @Override
 // notify all listener about the update
 public void setStatus(int status) {
 for ( GPSListener listener : this.listeners ) {
 listener.statusUpdated(status);
 }
 }

 // return the last known coordinate
 public Position getLastCoordinate() {
 return this.lastCoordinate;
 }

}

GPSListener.java

public interface GPSListener {

 void positionUpdated(Position position);

 void statusUpdated(int status);

}

LBSPositionObserver.java – native GPS interface

public interface LBSPositionObserver {

 void positionUpdated(Position position);

 void setStatus(int status);

}

Navigator.java

public class Navigator implements GPSListener {

 private NavigatorObserver observer;

 public Navigator(NavigatorObserver observer) {
 this.observer = observer;
 }

 // start navigation by listening to gps updates
 public void navigate(Route route) {
 GPSProvider gps = GPSProvider.GetInstance();
 gps.attach(this);
 }

 // pause navigation by not receiving gps updates
 public void pause() {
 GPSProvider gps = GPSProvider.GetInstance();
 gps.dettach(this);
 }

 @Override
 // everytime the position is updated, the navigator gives directions if needed
 public void positionUpdated(Position position) {
 // navigate user through route.
 int step = this.verifyStepUpdated();
 if ( step != -1 ) {
 this.observer.StepUpdated(step);
 }

 if ( this.achievedDestination() ) {
 this.observer.DestinationAchived(position);
 }
 }

 // calculate if achieved destination
 private boolean achievedDestination() {
 (...)
 }

 // verify is have to change direction
 private int verifyStepUpdated() {
 (...)
 }

 @Override
 public void statusUpdated(int status) {
 // send status to end user.
 }
}

Now, since I’ve finished my Navigator module, I want to test it to make sure it’s working correctly. In order to test the Navigator module, I need a GPS data log and a route to walk through it, simulating a person walking and being navigated by the system. The route is not a problem because I pass it as a parameter of “navigate” method. However, there is no way to simulate a GPS log with the code above, unless I use some Dependency Injection Framework, which is not the case.

That’s the Singleton disadvantage. I can’t inject a GPS mock in my Navigator module because I always use the native gps implementation represented in my Singleton GPSProvider class. Everytime I need some GPS information, I use the GPSProvider.GetInstance() static method to retrieve the only GPS instance I have access to.

To solve this problem, I found a simple solution: not using Singleton. I removed  the Singleton pattern from GPSProvider and change every class that uses GPSProvider.GetInstance() to receive the current GPS intance. In the Navigator module, I passed the GPS instance through its class’ constructor.

GPSAbstractProvider.java

import java.util.ArrayList;
import java.util.List;

public abstract class GPSAbstractProvider {

 private List<GPSListener> listeners;

 public GPSAbstractProvider() {
 this.listeners = new ArrayList<GPSListener>();
 }

 public abstract void initGPSService();

 public void attach(GPSListener listener) {
 this.listeners.add(listener);
 }

 public void dettach(GPSListener listener) {
 this.listeners.remove(listener);
 }

 public void notifyPositionUpdated(Position position) {
 for ( GPSListener listener : this.listeners ) {
 listener.positionUpdated(position);
 }
 }

 public void notifyStatusUpdated(int status) {
 for ( GPSListener listener : this.listeners ) {
 listener.statusUpdated(status);
 }
 }

}

GPSProvider.java

public class GPSProvider extends GPSAbstractProvider implements LBSPositionObserver {
 private Position lastCoordinate;

 private GPSProvider() {
 super();
 }

 @Override
 // perform GPS initialization
 public void initGPSService() {
 (...)
 }

 @Override
 public void positionUpdated(Position position) {
 this.lastCoordinate = position;
 this.notifyPositionUpdated(position);
 }

 @Override
 public void setStatus(int status) {
 this.notifyStatusUpdated(status);
 }

 public Position getLastCoordinate() {
 return this.lastCoordinate;
 }

}

Navigator.java

public class Navigator implements GPSListener {

 private NavigatorObserver observer;
 private GPSAbstractProvider gps;

 public Navigator(NavigatorObserver observer, GPSAbstractProvider gps) {
 this.observer = observer;
 this.gps = gps;
 }

 public void navigate(Route route) {
 this.gps.attach(this);
 }

 public void pause() {
 this.gps.dettach(this);
 }

 @Override
 public void positionUpdated(Position position) {
 // navigate user through route.
 int step = this.verifyStepUpdated();
 if ( step != -1 ) {
 this.observer.StepUpdated(step);
 }

 if ( this.achievedDestination() ) {
 this.observer.DestinationAchived(position);
 }
 }

 private boolean achievedDestination() {
 (...)
 }

 private int verifyStepUpdated() {
 (...)
 }

 @Override
 public void statusUpdated(int status) {
 // send status to end user.
 }
}

Much better! Notice that I still have just one single instance of my GPS class. All I have to do is creating my GPS at the beginning of the program and pass it through classes that use it.
Doing this, testing my code became very simple. I inject my GPS mock to simulate GPS data in my tests,  just as below.

NavigatorTest.java

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

public class NavigatorTest extends TestCase implements NavigatorObserver {

 private Navigator navigator;
 private GPSAbstractProvider gps;

 public void testNavigate() throws Exception {
 List<Position> gpsPositions = new ArrayList<Position>();
 this.addPositions(gpsPositions);
 this.gps = new GPSTestProvider(gpsPositions);

 this.navigator = new Navigator(this, this.gps);
 this.navigator.navigate(this.createSimpleRoute());

 gps.initGPSService();

 assert(...);
 assert(...);
 }

 private Route createSimpleRoute() {
 (...)
 }

 private void addPositions(List<Position> gpsPositions) {
 (...)
 }

 @Override
 public void DestinationAchived(Position destination) {
 (...)
 }

 @Override
 public void StepUpdated(int step) {
 (...)
 }

}

As you can see, I can use any GPS provider in my tests, making them much more easy and flexible.
In addition to the disavantage presented, Alex Miller discuss some points why he hates Singleton pattern.
From here, trying avoiding this pattern in situations like that. Think twice before applying Singleton in your project.

See you


Fernando

December 14, 2008

JavaScript Unit Testing with YUI Test

Filed under: testing, web — Tags: , , — nandokakimoto @ 2:44 pm

imagem

Hi,

some posts ago I talked about JavaScript and user interface testing using Selenium. Today, I will present another option to test your JavaScript code.

YUI Test is a testing framework for browser-based JavaScript solutions, providing JavaScript Unit Testing. While not a direct part from any specific xUnit framework, YUI Test does derive some characteristics from nUnit and JUnit.

Here are some of YUI Test features:

  • Rapid creation of test cases through simple syntax.
  • Advanced failure detection for methods that throw errors.
  • Grouping of related test cases using test suites.
  • Asynchronous tests for testing events and Ajax communication.
  • DOM Event simulation in all A-grade browsers.

To start using YUI Test, you must walkthrough some steps:

  1. Include required YUI Test files into your html created file
  2. Write your javascript piece of code
  3. Create a test case
  4. Execute tests

There is straightforward tutorial and a 48 minutes video presented by Yahoo! engineer Nicholas C. Zakas in YUI Blog. It’s a good opportunity to add some TDD to your JavaScript code and improve project quality and maintenance.

See you,


Fernando

September 9, 2008

Interface Unit Tests with Selenium

Filed under: testing, web — Tags: — nandokakimoto @ 3:50 am

Hi,

this week started with tests development, since I took the responsability of testing a Web Application. However, different from the others tests that I’ve done in the past, which covered C# code,  this ones are related to the project’s user interface. So, testing javascript code and interface functionality are now part of my work. Due to that, I found and amazing IDE with this puporse: let me show you Selenium.

“Selenium IDE is a Firefox addon that records clicks, typing, and other actions to make a test, which you can play back in the browser. Selenium IDE is not only recording tool: it is a complete IDE. You can choose to use its recording capability, or you may edit your scripts by hand”.

Here, is some of its features:

  • Easy record and playback
  • Intelligent field selection will use IDs, names, or XPath as needed
  • Autocomplete for all common Selenium commands
  • Walk through tests
  • Debug and set breakpoints
  • Save tests as HTML, Ruby scripts, Java, C# or any other format
  • Option to automatically assert the title of every page

All you have to do is to recorde yourself a test by doing some actions with your mouse and keyboard in a web page, and later reproduce the test as if you were doing the working again. With that, is possible to test almost everything you want to check in a html code, which means, in the interface of the web page.

Let’s do an easy example. First of all, install the firefox extension here. After restarting your firefox, let’s navigate to the google home page and open the Selenium IDE by clicking on Tools -> Selenium IDE. Remember to press the recorde button, as show in the picture below, to start recording the test.

Now, type “Talking about computer science” and press OK. Later, click on the first occurency of the search, redirecting you to my blog :)

Now, select “nandokakimoto” and with the rigth button choose “verifyTextPresent nandokakimoto”, which means that the test will look for this text when it runs.

It’s done! Now stop the test by clicking again on the record button in Selenium IDE. Take a  look at the set of commands shown in the table to verify if the are correct. Then, it’s time to run the test and see the result. So, click on the run icon, as show in the picture below, and you will see that the test run with success.

To see the test code in C#, Ruby or Java code, just click on Options -> Format and choose your prefered language. It’s really easy. Now, go forward and create your own interface tests.

See you,


Fernando

Blog at WordPress.com.