This 1 hour and 20 minute screencast guides you through a TDD Kata for designing with Model-View-Presenter pattern in iOS using the JetBrains AppCode IDE for objective-C and the OCMock static library.
The premise of this kata is that the existing ViewControllers in any iOS application are tightly coupled to presentation layer concerns. Rather than attempting to write tests directly against the view controllers, instead write unit tests to generate a Presenter class, injected with multiple protocols, that will coordinate activities between those protocols. In this classic "bank account transfer" example, the presenter delegates method calls to a remote account repository protocol, a local account repository protocol, and a view protocol. The use of OCMock to mock these protocols enables us to design and understand the interactions, and to "generate-by-usage" each element of the MVP pattern. Later in the kata an IOC container class, "ServiceLocator", is designed by unit test to standardize presenter instantiation in a single location.
This kata uses the JetBrains AppCode IDE to generate all tests and code. The kata has a heavy emphasis on effective use of keyboard shortcuts to generate classes, protocols, methods and import statements quickly and naturally as part of the design process. Please note that in this screencast, the key mappings have been set to the standard Intellij keymap used by Intellij (java). This keymap is often set as the default in other JetBrains IDEs. (JetBrains provides IDEs in multiple programming languages.)
To begin the kata screencast, click here.
Monday, December 03, 2012
Monday, February 13, 2012
TDD with Objective-C and Calculator Kata (using JetBrains' AppCode)
I've just created a 1 hour tutorial/screencast that demonstrates TDD in objective-C (iOS 5) via Roy Osherove's Calculator Kata. The screencast primarily uses JetBrains' new AppCode IDE for objective-C, but it also flips occasionally into XCode 4.2 to set up a storyboard with a simple UIViewController that connects to the TDD-created Calculator class.
The screencast demonstrates a variety of layouts and keyboard shortcuts for AppCode (and to a lesser extent, XCode) as well as covering a number of language features of objective-C.
Please have a look, and if you have any questions, send me a comment at my twitter account.
Screencast: Learning Objective-C via TDD and Calculator Kata
The screencast demonstrates a variety of layouts and keyboard shortcuts for AppCode (and to a lesser extent, XCode) as well as covering a number of language features of objective-C.
Please have a look, and if you have any questions, send me a comment at my twitter account.
Screencast: Learning Objective-C via TDD and Calculator Kata
Sunday, February 12, 2012
DDD Kata, Part 4 (Service Layer with Mocks)
Pre-Requisite: DDD Kata Part 3
Kata Review
In part 2 of the kata, you built a simple service test to demonstrate the passing of the Item from the Inventory aggregate root to the Invoice aggregate root. In part 3 of the kata, you created IUnitOfWork interface to manage atomic transactions with commit and rollbacks.
Now we need to design the real service.
In this test we will "inject" repository interfaces into the service class constructor to do the work of persisting the state changes to our domain entities. The UnitOfWork we created in part 3 of the kata will assist us in this effort.
Completed kata example on github: DDD Kata Part 4 sample code (github)
NOTE If you haven't already download RhinoMocks, download it and add the DLLs to a 3rd Party Libs directory for reference.
1. Open the previous solution you created in kata 3.
2. Add a reference to RhinoMocks.DLL to the library "Kata.Services.Tests.Unit".
3. Use RhinoMocks to mock the following interfaces (use Resharper to generate the new ones).
NOTE Your mocking levels are stub, dynamic, and strict. The 3rd choice strictly enforces the test specfiications. Start with a strict implementation for now.
4. Create a test.
5. Enter code comments, and basic Rhino Mocks method calls, to generate a test skeleton:
Now populate the test skeleton as follows:
6. In declare constants, create constants for productCode and serialNumber
7. In declare constants, build an Inventory instance using method StockItemBy()
8. In declare constants, create an Invoice
9. RhinoMocks tests based on object equality, so make sure you have assigned Ids to all your objects.
10. In expectations, expect that IUnitOfWorkFactory creates IUnitOfWork.
12. Add comment: // Call to Inventory.PullItemBy(productCode)
13. Add comment: // Call to Invoice.BillItem(item)
15. Expect that IUnitOfWork.Commit() is called
17. Between ReplayAll and VerifyAll, create InvoicingService instance with all mocked interfaces.
18. Now use Resharper to generate the method under test: InvoicingService.CreateSimpleInvoice(productCode,serialNumber).
19. Run the test and watch it fail.
20. Use the expectations set in the test to assemble the method.
21. Remember to wrap the call in IUnitOfWork using statement, and to commit at end of the block
22. Invoice will fail because its Id cannot be known, so MODIFY the expectation for InvoiceRepository.Save() by adding:
LastCall.IgnoreArguments();
23. All tests should now pass.
This completes DDD kata part 3.
The next kata will introduce Fluent NHibernate as an implementation framework against the domain entities and repository interfaces that you have created so far.
Kata Review
In part 2 of the kata, you built a simple service test to demonstrate the passing of the Item from the Inventory aggregate root to the Invoice aggregate root. In part 3 of the kata, you created IUnitOfWork interface to manage atomic transactions with commit and rollbacks.
Now we need to design the real service.
In this test we will "inject" repository interfaces into the service class constructor to do the work of persisting the state changes to our domain entities. The UnitOfWork we created in part 3 of the kata will assist us in this effort.
Completed kata example on github: DDD Kata Part 4 sample code (github)
NOTE If you haven't already download RhinoMocks, download it and add the DLLs to a 3rd Party Libs directory for reference.
1. Open the previous solution you created in kata 3.
2. Add a reference to RhinoMocks.DLL to the library "Kata.Services.Tests.Unit".
3. Use RhinoMocks to mock the following interfaces (use Resharper to generate the new ones).
NOTE Your mocking levels are stub, dynamic, and strict. The 3rd choice strictly enforces the test specfiications. Start with a strict implementation for now.
- IInvoiceRepository
- IInventoryRepository
- IUnitOfWorkFactory
- IUnitOfWork
private MockRepository _mockRepository;
private IInvoiceRepository _invoiceRepository;
private IInventoryRepository _inventoryRepository;
private IUnitOfWorkFactory _unitOfWorkFactory;
private IUnitOfWork _unitOfWork;
[SetUp]
public void SetUp()
{
_mockRepository = new MockRepository();
_invoiceRepository = _mockRepository.StrictMock();
_inventoryRepository = _mockRepository.StrictMock();
_unitOfWorkFactory = _mockRepository.StrictMock();
_unitOfWork = _mockRepository.StrictMock();
}
4. Create a test.
5. Enter code comments, and basic Rhino Mocks method calls, to generate a test skeleton:
[Test]
public void CreateSimpleInvoiceMethod_ProductCodeAndSerialNumberInputs_GenratesSimpleInvoice()
{
// declare constants
// expectations
_mockRepository.ReplayAll();.
// call to new service method
_mockRepository.VerifyAll();
}
Now populate the test skeleton as follows:
6. In declare constants, create constants for productCode and serialNumber
7. In declare constants, build an Inventory instance using method StockItemBy()
8. In declare constants, create an Invoice
9. RhinoMocks tests based on object equality, so make sure you have assigned Ids to all your objects.
// declare constants
const string productCode = "ABCD1234";
const string serialNumber = "BB2135315";
var inventory = new Inventory { Id = 1234 };
inventory.StockItemBy(productCode, serialNumber);
var invoice = new Invoice() { Id = 1234 };
10. In expectations, expect that IUnitOfWorkFactory creates IUnitOfWork.
NOTE If the Create() method exists on the implementation class (UnitOfWorkFactory) but not on the interface, use Resharper to generate it on the interface.11. Expect that InventoryRepository.LoadInventoryByProduct(IUnitOfWork uow, string productCode) returns Inventory instance.
12. Add comment: // Call to Inventory.PullItemBy(productCode)
13. Add comment: // Call to Invoice.BillItem(item)
NOTE These must be comments only as they aren't on mock objects. Actual calls would reduce inventory to zero in no context and cause a null error below.14. Expect that InvoiceRepository.Save(IUnitOfWork uow, Invoice invoice) saves invoice.
15. Expect that IUnitOfWork.Commit() is called
NOTE If the Commit() method exists on the implementation class (UnitOfWork) but not on the interface, use Resharper to generate it on the interface.16. Expect that IUnitOfWork.Dispose() is called
// expectations
Expect.Call(_unitOfWorkFactory.Create()).Return(_unitOfWork);
Expect.Call(_inventoryRepository.LoadInventoryByProduct(_unitOfWork, productCode)).Return(inventory);
// Call to Inventory.PullItemBy(productCode)
// Call to Invoice.BillItem(item)
_invoiceRepository.Save(_unitOfWork, invoice);
_unitOfWork.Commit();
_unitOfWork.Dispose();
17. Between ReplayAll and VerifyAll, create InvoicingService instance with all mocked interfaces.
_mockRepository.ReplayAll();
var sut = new InvoicingService(_unitOfWorkFactory, _inventoryRepository, _invoiceRepository);
Invoice actualInvoice = sut.CreateSimpleInvoice(productCode, serialNumber);
_mockRepository.VerifyAll();
18. Now use Resharper to generate the method under test: InvoicingService.CreateSimpleInvoice(productCode,serialNumber).
19. Run the test and watch it fail.
20. Use the expectations set in the test to assemble the method.
21. Remember to wrap the call in IUnitOfWork using statement, and to commit at end of the block
public Invoice CreateSimpleInvoice(string productCode, string serialNumber)
{
using(IUnitOfWork unitOfWork = _unitOfWorkFactory.Create())
{
Inventory inventory = _inventoryRepository.LoadInventoryByProduct(unitOfWork, productCode);
Item item = inventory.PullItemBy(productCode);
var invoice = new Invoice();
invoice.BillItem(item);
_invoiceRepository.Save(unitOfWork, invoice);
unitOfWork.Commit();
return invoice;
}
}
22. Invoice will fail because its Id cannot be known, so MODIFY the expectation for InvoiceRepository.Save() by adding:
LastCall.IgnoreArguments();
23. All tests should now pass.
This completes DDD kata part 3.
The next kata will introduce Fluent NHibernate as an implementation framework against the domain entities and repository interfaces that you have created so far.
DDD Kata, Part 3 (build atomic transaction manager i.e. UnitOfWork)
Pre-requisite: DDD Kata Part 2
Kata Focus
1) Work occurs in the Repository layer, which will be used to persist to and from a data store. The data store will be encapsulated behind interfaces.
2) A pre-requisite activity is to build a wrapper interface to encapsulate transaction commit/rollback, with commit and rollback occurring on Dispose().
Completed kata example on github: DDD Kata Part 3 sample code (github)
The Kata
Time goal: under 30 minutes
Repository layer
1. Create new class libraries:
We will start by creating the interface to wrap transaction commits and rollbacks. For an initial, simple name, we'll use AtomicTransactionManager. In a few minutes we will refactor that to use the name of the corresponding design pattern.
Repository: AtomicTransactionManager
1. In the new Repository unit test library, create class AtomicTransactionManagerTests.cs
2. Verify that AtomicTransactionManager is instance of IAtomicTransactionManager.
3. Verify that the constructor of AtomicTransactionManager sets TransactionState property to “Is Begun”.
6. Verify that IUnitOfWork is instance of IDisposable
7. Verify that the Dispose() method sets TransactionState property to “RolledBack”.
8. Verify that calling first the Commit() method, then the Dispose() method, sets TransactionState Property to “Committed”.
UnitOfWorkFactory
Use a factory class to encapsulate the generation of the IUnitOfWork.
9. Verify that UnitOfWorkFactory is instance of IUnitOfWorkFactory.
10. Verify that IUnitOfWorkFactory.Create() returns an IUnitOfWork instance.
Part 3 of the kata is complete.
In the next kata, we will build the service layer with repository interfaces and mock objects.
Continue with DDD Kata Part 4
Kata Focus
1) Work occurs in the Repository layer, which will be used to persist to and from a data store. The data store will be encapsulated behind interfaces.
2) A pre-requisite activity is to build a wrapper interface to encapsulate transaction commit/rollback, with commit and rollback occurring on Dispose().
Completed kata example on github: DDD Kata Part 3 sample code (github)
The Kata
Time goal: under 30 minutes
Repository layer
1. Create new class libraries:
- Kata.Repository.Tests.Unit
- Kata.Repository
We will start by creating the interface to wrap transaction commits and rollbacks. For an initial, simple name, we'll use AtomicTransactionManager. In a few minutes we will refactor that to use the name of the corresponding design pattern.
Repository: AtomicTransactionManager
1. In the new Repository unit test library, create class AtomicTransactionManagerTests.cs
2. Verify that AtomicTransactionManager is instance of IAtomicTransactionManager.
3. Verify that the constructor of AtomicTransactionManager sets TransactionState property to “Is Begun”.
NOTE You should be using Resharper's "generate-by-usage" (alt-Enter) to generate these properties and methods of the sut. However, make sure that the declared type on the sut is interface, otherwise your generate-by-usage will create class-only properties and methods. It should be creating the properties and methods on the interface.4. Verify that Commit() method sets TransactionState property to “CommitRequested”
The actual name for this design pattern is UnitOfWork. You can read about it here: Martin Fowler, PEAA: Unit of Work5. Refactor the class and interface you have created so far to UnitOfWork and IUnitOfWork
6. Verify that IUnitOfWork is instance of IDisposable
7. Verify that the Dispose() method sets TransactionState property to “RolledBack”.
8. Verify that calling first the Commit() method, then the Dispose() method, sets TransactionState Property to “Committed”.
UnitOfWorkFactory
Use a factory class to encapsulate the generation of the IUnitOfWork.
9. Verify that UnitOfWorkFactory is instance of IUnitOfWorkFactory.
10. Verify that IUnitOfWorkFactory.Create() returns an IUnitOfWork instance.
Part 3 of the kata is complete.
In the next kata, we will build the service layer with repository interfaces and mock objects.
Continue with DDD Kata Part 4
Subscribe to:
Posts (Atom)