Introduction

You are currently browsing the weblog archives for January, 2005.

Archive for January, 2005

Tuesday, January 4th, 2005

Test Driven Development (TDD) and Unit Testing with Mock Objects in Practice

cheap cialis pill certified cialis cheap viagra in canada cialis buy drug buy generic cialis viagra buy 25mg viagra cheap viagra without prescription buy cheapest viagra on line purchase viagra cialis 10mg buying generic viagra cialis pills viagra from india cheapest sildenafil citrate cheap cialis no rx viagra india cialis bangkok viagra for order buy sildenafil internet buy generic viagra online buying cialis online where to order cialis tablet cialis find cialis no prescription required viagra cheap drug order cialis cheap online online pharmacy cialis cialis no rx order generic cialis price of cialis viagra soft drug viagra cheap viagra from uk order cialis no prescription order cheap viagra viagra drug order cheap cialis cheap cialis pharmacy best price for viagra cheap viagra from usa cost cialis cialis overnight shipping cheapest generic cialis online generic viagra online online viagra viagra sales cheap cialis in canada compare cialis prices online cialis online drug viagra online purchase discount cialis without prescription no rx viagra cialis overnight viagra uk cialis order cheap cialis from usa buying cialis cialis overnight delivery cialis in bangkok buy and purchase sildenafil online impotence treatment cheap price viagra viagra sale cheap cialis tablet drug cialis generic cialis online cheap viagra pharmacy find discount cialis online viagra malaysia cialis without a prescription buy cialis online cheap viagra rx buy no rx viagra cialis 20mg viagra in malaysia discount viagra online buy sildenafil cheap buy viagra low price buy cialis cialis cheap price cialis cheap generic viagra cialis canada low cost viagra buy cheap viagra cialis vs viagra order cialis from us cialis tablets find no rx cialis buy generic cialis online buy viagra overnight delivery cheapest cialis price buy cheapest cialis on line order cialis in canada viagra tablet viagra no online prescription find cheap cialis online viagra price order viagra no prescription cheap generic cialis buy viagra online cheap cialis uk cialis without rx generic cialis cheap viagra vs cialis order cialis on internet viagra tablets viagra purchase impotence drugs buy cialis generic cialis tablet cialis cheapest price order viagra from canada viagra generic cheap viagra from canada order cialis compare viagra prices online find cheap cialis impotence cure pfizer viagra find discount cialis cheapest cialis buy cialis from india impotence buy cheapest viagra online cialis side effects viagra order discount cialis online cialis in malaysia cialis in uk viagra in uk cialis online without prescription cialis online pharmacy order viagra buy viagra online viagra side effects cialis sale discount cialis no rx cheapest viagra find cialis order cialis no rx buy cialis low price buy viagra cheap drug cialis online purchase order discount viagra online 50 mg viagra 100 mg viagra 10mg cialis cost of cialis cheapest cialis prices buy discount viagra online cialis sales 50mg viagra cialis price buy viagra on internet cialis pill cheapest cialis online purchase viagra overnight delivery cheap cialis from canada cheapest viagra price cialis 20 mg buy sildenafil low cost order viagra without prescription buy viagra lowest price no prescription cialis order viagra on internet discount cialis overnight delivery cialis cheap drug viagra approved viagra no rx required compare viagra prices no rx cialis cheap cialis on internet buy viagra from india buy discount cialis online viagra pharmacy online order viagra from us cialis free delivery cialis for order buy cialis from canada viagra without rx viagra online review 10 mg cialis cheap viagra no rx cheapest viagra prices viagra prices cialis pharmacy order no rx cialis buy cialis in us buy cialis no prescription required order cialis from canada lowest price cialis cheap cialis internet online pharmacy viagra cheapest generic cialis generic drugs cialis india find cialis without prescription best price cialis buy viagra without prescription cheap cialis in uk where to buy viagra 20 mg cialis cheap cialis from uk buy sildenafil canada cialis no rx required cialis in us buy cialis overnight delivery cialis cheap price order cheap viagra online 20mg cialis buy cheap viagra online viagra internet viagra without prescription free cialis buy cialis us cialis buy buy viagra in canada order viagra cheap online find viagra without prescription viagra pills cheap cialis no prescription viagra online without prescription order generic viagra cialis discount viagra cheapest price purchase viagra no rx viagra no rx viagra cheap discount viagra overnight delivery sale cialis cialis pharmacy online purchase cialis without prescription pharmacy online cialis medication discount viagra buy cheap cialis impotence medication viagra medication find cialis on internet impotence pills cialis prices discount viagra without prescription cialis online cheap cialis online review find cheap viagra online buy viagra us purchase cialis online certified viagra where to order viagra buy cheapest viagra buy cialis internet order cialis online buy sildenafil online buy cialis cheap cheap viagra purchase cialis find discount viagra buy cialis on internet cialis buy online buy sildenafil online without a prescription viagra buy online order cheap cialis online viagra information no prescription viagra cost of viagra buy cialis in canada buy cialis online buy viagra cheapest generic viagra cialis us cialis australia fda approved cialis lowest price for viagra viagra bangkok cialis prescription cialis cost buy no rx cialis buy viagra internet viagra discount order viagra overnight delivery generic cialis viagra australia 25 mg viagra order viagra online viagra overnight cialis rx order cialis in us order viagra no rx order discount cialis online viagra vendors order viagra in us buy sildenafil in uk viagra us buy generic viagra viagra canada viagra no prescription viagra cheap price cheap viagra tablet viagra free delivery overnight viagra purchase viagra online find cheap viagra cialis malaysia best price viagra cialis free sample find viagra on internet cialis generic buy sildenafil in canada order cialis no prescription required cheapest viagra online purchase cialis no rx viagra in us order discount cialis cheap viagra internet free viagra cialis approved best price for cialis cialis from india find no rx viagra generic viagra viagra from canada viagra online pharmacy buy viagra from canada cheapest generic viagra online buy cheapest cialis discount cialis viagra overnight delivery cialis without prescription 100mg viagra cialis in australia price of viagra order cialis overnight delivery cheap viagra in uk buying generic cialis viagra pill buy cialis on line low cost cialis find discount viagra online buying viagra cheap cialis overnight delivery pharmacy cialis cheap viagra pill viagra prescription find viagra online buy cialis lowest price discount viagra no rx online cialis viagra free sample cheap viagra in usa find viagra cheap viagra online buy viagra no rx generic viagra cheap buy cialis without prescription buy viagra in us cheap viagra overnight delivery cheap cialis in usa cheap cialis online viagra order no rx viagra viagra soft tab find cialis online lowest price viagra cialis drug cialis vendors viagra online stores erectile dysfunction order viagra in canada buy viagra on line viagra overnight shipping viagra online cheap lowest price for cialis approved viagra pharmacy cialis 10 mg cialis no online prescription cialis purchase cialis from canada order cialis without prescription viagra for sale viagra in australia approved cialis pharmacy buy viagra generic buy sildenafil in spain find viagra no prescription required cialis no prescription buy viagra from us order viagra no prescription required cost viagra purchase viagra without prescription buy cialis no rx cialis cheap cialis internet tablet viagra cheap viagra on internet viagra cost pharmacy viagra cialis soft tab cialis information buy cheap cialis internet purchase cialis overnight delivery cheap cialis without prescription buy viagra no prescription required compare cialis prices buy cheap cialis online overnight cialis where to buy cialis cheap cialis buy cheap viagra internet buy discount cialis viagra buy drug cheap viagra no prescription buy sildenafil citrate buying viagra online buy discount viagra fda approved viagra cialis online stores cheap cialis tablets buy cheapest cialis online cheap viagra tablets order discount viagra sale viagra viagra online cialis for sale cialis soft viagra pharmacy buy cialis from us viagra without a prescription viagra in bangkok

When your boss confronts you with a task you must handle, the first thing you do is thinking about it. You mediate on the task and try to find the best solution of doing it. You maybe draw some sketches to visualize the whole thing and get a clearer image.
But, what’s next? - Well, when practicing TDD the next thing (actually the first, but I’m not that pragmatic about it) is to write a test for the central class and methods. This helps a lot because, when writing a test you become aware of collaborators, you test all special cases and you do not introduce unnecessary complexity. You basically create the whole api and implementations by working with them, which leads to an easy to use api that is based on a practical ground.
That’s basically all about it.
You first write your tests for a method of a class, and then the actual method based on the test, until the test executes without causing errors. Then the test for the next method and so on. It’s an easy, intuitive (when you are used to it) and safe way of programming which leads to stable and easy to use code. Another bonus is that when you refactor your code, improve its performance or do some other changes you can always run the tests to see if everything is still working.
This article is supposed to be a practical one (at least that’s what the headline says), thus we will jump right into practicing TDD. All you need is the as2lib’s unit testing framework and the mock objects framework from the last article Unit Testing: Mock Objects Framework.
A request came from a bank that needs an application to do their banking transactions like transfering money onto an account. The account seems to be the central problem domain (btw. we are only going to build the domain model). The bank clerk must be able to book money to an account (credit) and to withdraw money from an account (debit). That said we can start writing our tests for the account’s constructor and the methods credit and debit. We will start with the constructor tests.

  1. import org.as2lib.test.unit.TestCase;
  2. import org.as2lib.test.mock.MockControl;
  3. import com.simonwacker.banking.Account;
  4.  
  5. class com.simonwacker.banking.AccountTest extends TestCase {
  6.  
  7.   public function testNew(Void):Void {
  8.     var account:Account = new Account();
  9.     assertSame(account.getBalance(), 0);
  10.   }
  11.  
  12. }

We want the account’s constructor to take no arguments and set the balance to zero. To be able to control that the balance is zero we need the ,getBalance’ method. But the compiler won’t compile. That’s because we have not created the ,Account’ class yet. That’s what we are going to do now, based on our first test.

  1. class com.simonwacker.banking.Account {
  2.  
  3.   public function Account(Void) {
  4.   }
  5.    
  6.   public function getBalance(Void):Number {
  7.     return 0;
  8.   }
  9.  
  10. }

The compiler does not complain anymore and when we execute the test everything seems to work.
To execute the test you need a fla with the following code in the first frame.

  1. import org.as2lib.test.unit.TestSuiteFactory;
  2.  
  3. com.simonwacker.banking.AccountTest;
  4. new TestSuiteFactory().collectAllTestCases().run();

It’s time to write the test for the ,credit’ method.

  1. public function testCreditWithNullAmount(Void):Void {
  2.   var account:Account = new Account();
  3.   account.credit(null);
  4.   assertSame(account.getBalance(), 0);
  5. }

The credit method takes one argument ,amount’. Thus the first thing to test is what happens if we pass-in an ,amount’ of value ,null’. I want the method to just do nothing. That means that after invoking this method the balance should still be zero.
To satisfy the compiler and the test we implement the ,credit’ method.

  1. public function credit(amount:Number):Void {
  2.   balance += amount;
  3. }

Everything works fine now and we are ready for the next test that passes an amount of 40.

  1. public function testCreditWithRealAmount(Void):Void {
  2.   var account:Account = new Account();
  3.   account.credit(40);
  4.   assertSame(account.getBalance(), 40);
  5. }

Executing the test fails. We need to do some major changes. To get it working we must be able to change the balance through the ,credit’ method dynamically.

  1. class com.simonwacker.banking.Account {
  2.  
  3.   private var balance:Number;
  4.  
  5.   public function Account(Void) {
  6.     balance = 0;
  7.   }
  8.  
  9.   public function credit(amount:Number):Void {
  10.     balance += amount;
  11.   }
  12.  
  13.   public function getBalance(Void):Number {
  14.     return balance;
  15.   }
  16.  
  17. }

When we run our test again we get the following output:

  1. ** InfoLevel **
  2. *** TestSuite <Generated TestSuite> (1 Tests) [5ms] ***
  3.   com.simonwacker.banking.AccountTest run in [5ms]. 1 error occured
  4.      testCreditWithNullAmount() [2ms] 1 error occured
  5.        assertSame failed!
  6.          NaN !== 0
  7.      
  8. *******************************************************

Out ,credit’ method does something wrong. It adds the amount to the balance even if it is ,null’. We have to prevent this.

  1. public function credit(amount:Number):Void {
  2.   if (amount != null) {
  3.     balance += amount;
  4.   }
  5. }

We enhance our ,testCreditWithRealAmount’ test and add a new one to be really really sure that everything works as expected.

  1. public function testCreditWithNotZeroBalanceAndNullAmount(Void):Void {
  2.   var account:Account = new Account();
  3.   account.credit(60);
  4.   account.credit(null);
  5.   assertSame(account.getBalance(), 60);
  6. }
  7.  
  8. public function testCreditWithRealAmount(Void):Void {
  9.   var account:Account = new Account();
  10.   account.credit(40);
  11.   assertSame(account.getBalance(), 40);
  12.   account.credit(30);
  13.   assertSame(account.getBalance(), 70);
  14. }

A business rule prescribes that the boss of the bank shall get notified if someone credits an amount that’s bigger or equal than 1 000 000 dollars to thank this guy personally. That notification is an email to the boss.
There already exists support for sending emails. This support is based on the ,EmailSender’ interface.

  1. interface com.simonwacker.banking.EmailSender {
  2.  
  3.   public function sendEmail(message:String):Void;
  4.  
  5. }

We write a test for the ,credit’ method in which we verify that the email sender’s ,sendEmail’ method gets executed when we credit an amount bigger than 1 000 000 dollar.

  1. public function testCreditWithAmountBiggerThanOneMillionDollars(Void):Void {
  2.   var emailSenderControl:MockControl = new MockControl(EmailSender);
  3.   var emailSender:EmailSender = emailSenderControl.getMock();
  4.   emailSender.sendEmail("Someone transfered 1 000 000 dollars.");
  5.   emailSenderControl.replay();
  6.  
  7.   var account:Account = new Account();
  8.   account.setEmailSender(emailSender);
  9.   account.credit(1500000);
  10.  
  11.   emailSenderControl.verify();
  12. }
  13.  
  14. public function testCreditWithAmountEqualToOneMillionDollars(Void):Void {
  15.   var emailSenderControl:MockControl = new MockControl(EmailSender);
  16.   var emailSender:EmailSender = emailSenderControl.getMock();
  17.   emailSender.sendEmail("Someone transfered 1 000 000 dollars.");
  18.   emailSenderControl.replay();
  19.  
  20.   var account:Account = new Account();
  21.   account.setEmailSender(emailSender);
  22.   account.credit(1000000);
  23.  
  24.   emailSenderControl.verify();
  25. }
  26.  
  27. public function testCreditWithAmountLessThanMillionDollars(Void):Void {
  28.   var emailSenderControl:MockControl = new MockControl(EmailSender);
  29.   var emailSender:EmailSender = emailSenderControl.getMock();
  30.   emailSenderControl.replay();
  31.  
  32.   var account:Account = new Account();
  33.   account.setEmailSender(emailSender);
  34.   account.credit(500000);
  35.  
  36.   emailSenderControl.verify();
  37. }

Because we are trained now we can make bigger steps and implement mutliple tests at once. The compiler complains because we have no method called ,setEmailSender’. Thus we introduce this method first.

  1. import com.simonwacker.banking.EmailSender;
  2.  
  3. class com.simonwacker.banking.Account {
  4.  
  5.   private var balance:Number;
  6.   private var emailSender:EmailSender;
  7.  
  8.   public function Account(Void) {
  9.     balance = 0;
  10.   }
  11.  
  12.   public function setEmailSender(emailSender:EmailSender):Void {
  13.     this.emailSender = emailSender;
  14.   }
  15.  
  16.   public function credit(amount:Number):Void {
  17.     if (amount != null) {
  18.       balance += amount;
  19.     }
  20.   }
  21.  
  22.   public function getBalance(Void):Number {
  23.     return balance;
  24.   }
  25.  
  26. }

When we run the test again we get the following output:

  1. ** InfoLevel **
  2. *** TestSuite <Generated TestSuite> (1 Tests) [26ms] ***
  3.   com.simonwacker.banking.AccountTest run in [26ms]. 2 errors occured
  4.      testCreditWithAmountBiggerThanOneMillionDollars() [11ms] 1 error occured
  5.        com.simonwacker.banking.AccountTest.testCreditWithAmountBiggerThanOneMillionDollars() threw a unexpected exception.
  6.          Expectation failure on verify:
  7.            sendEmail(Someone transfered 1 000 000 dollars.): expected: 1, actual: 0
  8.      
  9.      testCreditWithAmountEqualToOneMillionDollars() [5ms] 1 error occured
  10.        com.simonwacker.banking.AccountTest.testCreditWithAmountEqualToOneMillionDollars() threw a unexpected exception.
  11.          Expectation failure on verify:
  12.            sendEmail(Someone transfered 1 000 000 dollars.): expected: 1, actual: 0
  13.      
  14. ********************************************************

There’s still the sending functionality missing. We add it.

  1. public function credit(amount:Number):Void {
  2.   if (amount != null) {
  3.     if (amount >= 1000000) {
  4.       emailSender.sendEmail("Someone transfered 1 000 000 dollars.");
  5.     }
  6.     balance += amount;
  7.   }
  8. }

Executing the tests causes no errors now.

  1. ** InfoLevel **
  2. *** TestSuite <Generated TestSuite> (1 Tests) [18ms] ***
  3.   com.simonwacker.banking.AccountTest run in [18ms]. no error occured
  4. ********************************************************

That’s it. ;)
But there are still some things that we have not considered yet. What is if an email sender of value ,null’ gets set? What is if someone ,credits’ a negative amount?

In real life as you get more experienced writing tests and writing code you will just skip some of the little steps and combine them.

Download the sample code for Unit Testing with Mock Objects in Practice and Test Driven Development (TDD).
Download the as2lib snapshot from the 01.01.2005 which contains the unit testing and mock objects frameworks.

Saturday, January 1st, 2005

Unit Testing: Mock Objects Framework

Unit testing means testing a class in isolation. To be able to do this any collaborator must at least be replaced by some kind of stub implementation of it. While this is definitely a good thing and appropriate in some cases it is really awkward if you have many collaborators and if these collaborators have a rather large number of methods.
Another problem with stubs is that they are not flexible enough to meet every use case, especially the special ones that hardly ever occur (except you spent hours programming the stub).
Thus you need a more general and dynamic approach.

The solution is: Mock Objects.

Mock objects also take unit testing a step further. You do not just create a stub that acts as if it were real, you also verify that the class under test collaborates with the mock object in the expected way. That means for example that the class under test calls certain methods with certain arguments on the mock object.
To work efficiently with mock objects you of course need a framework that gives you the ability to create mock objects and work with them easily.
This article is about such a framework that is based on the approach the EasyMock Framework uses. So, if you have ever worked with easymock (it’s for Java) you should have no problem working with this one. The basic workflow is as follows:
Create a mock control for a specific class or interface, get the mock object from it, set your expectations, set the behavior of the mock object, switch to replay state, use the mock object as if it were a normal instance of your class and verify if all expectations have been met.
While this sounds a little complicated and awkward at first sight it really is not. Just take a look at the following demonstration:

  1. import org.as2lib.test.mock.MockControl;
  2.  
  3. // create mock control for class MyClass
  4. var myMockControl:MockControl = new MockControl(MyClass);
  5. // receive the mock object (it is in record state)
  6. var myMock:MyClass = myMockControl.getMock();
  7. // expect a call to the setStringProperty-method with argument ‘myString’.
  8. myMock.setStringProperty("myString");
  9. // expect calls to the getStringProperty-method
  10. myMock.getStringProperty();
  11. // return ‘myString’ for the first two calls
  12. myMockControl.setReturnValue("myString", 2);
  13. // throw MyException for any further call
  14. myMockControl.setDefaultThrowable(new MyException());
  15. // switch to replay state
  16. myMockControl.replay();
  17.  
  18. // the class under test calls these methods on the mock
  19. myMock.setStringProperty("myString");
  20. myMock.getStringProperty();
  21. myMock.getStringProperty();
  22.  
  23. // verify that alle expectations have been met
  24. myMockControl.verify();

If any expectation has not been met an AssertionFailedError gets thrown that explains what went wrong. In the above case no AssertionFailedError should be thrown because every expectation has been met but it hadn’t if we had called the getStringProperty-method only once on the myMock-mock.

There is much more that can be done with the framework but just refer to the api documentation that is included in the download (I generated it with the old version of as2api because the new does not work and it is thus a little complex. It may be clearer to open the as-file directly and take a look at the documentation there.).

Download the Mock Objects Framework for Flash (It’s actually a snapshot of the as2lib from the 01.01.2005. The mock objects framework is contained in the org.as2lib.test.mock package).