Tuesday, August 16, 2011

The difference between a mock and a stub


Using stubs – is the classic TDD approach where unit tests are designed to check state. A general core workflow would be calling a method of an object/type with subsequent verification that the state has been updated.
Using mocks – is a TDD variation - BDD - that aims to track behaviour. Typical scenario would be creating a pre-programmed workflow and check if a real-world object follows the predefined behaviour.
What is better? Which path to choose? These are debatable questions and are highlighted by Martin in his article “Mocks Aren't Stubs”.

Rhino Mocks:

Rhino Mocks is a dynamic mock object framework for the .Net platform. Its purpose is to ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing.


What is a mocked object?


Mock objects take stubs to an extreme and are used to set and verify expectations on interactions with model code



The need for mock objects:
A Mock Object:
  1. is easily created
  2. is easily set up
  3. is quick
  4. is deterministic
  5. has easily caused behavior
  6. has no direct user interface
  7. is directly queriable
You may want to use a Mock Object if the:
  1. real object has non-deterministic behavior
  2. real object is difficult to set up
  3. real object has behavior that is hard to cause (e.g., network error) (similar to 1)
  4. real object is slow
  5. real object has (or is) a UI
  6. test needs to query the object, but the queries are not available in the real object (e.g., "was this callback called?") (This needs a Mock Object that has *more* stuff than the real object; the other cases usually require a stub that is far smaller than the real object).
  7. real object acts "normal" most of the time, but once a month (or even less often) it does something "exceptional". We want Unit Tests to make sure the rest of the system does the Right Thing whether or not the object is acting "normal" or "exceptional". (Is this the same as #2 ?)
  8. real object does not yet exist
Mock objects are used in Unit Testing to isolate tests. Mock Objects allows you to test just the specific class / method without testing (and setting up, and tearing down, etc) the entire environment. Here is a simple example of using mock objects:



Benefits of Mocking:
  • Recognized testing pattern
  • Encourage passing objects as method parameters rather than making references to them part of our object state.
  • Mock objects tend to drive your classes into a highly compositional design with lots of little pieces and lots of interface surface
  • Encourage lightweight classes and more flexible methods.

Friday, August 12, 2011

When to Use Extreme Programming


Extreme Programming is useful in the following situations:
  • When the customer does not have a clear understanding of the details of the new system. The developers interact continuously with the customer, delivering small pieces of the application to the customer for feedback, and taking corrective action as necessary.
  • When the technology used to develop the system is new compared to other technologies. Frequent test cycles in Extreme Programming mitigate the risk of incompatibility with other existing systems.
  • When you can afford to create automated unit and functional tests. In some situations, you may need to change the system design so that each module can be tested in isolation using automated unit tests.
  • When the team size is not very large (usually 2 to 12 people). Extreme Programming is successful in part because it requires close team interaction and working in pairs. A large team would have difficulty in communicating efficiently at a fast pace. However, large teams have used Extreme Programming successfully.

Extreme Programming


In Extreme Programming, rather than designing whole of the system at the start of the project, the preliminary design work is reduced to solving the simple tasks that have already been identified.
The developers communicate directly with customers and other developers to understand the initial requirements. They start with a very simple task and then get feedback by testing their software as soon as it is developed. The system is delivered to the customers as soon as possible, and the requirements are refined or added based on customer feedback. In this way, requirements evolve over a period of time, and developers are able to respond quickly to changes.
The real design effort occurs when the developers write the code to fulfill the specific engineering task. The engineering task is a part of a greater user story (which is similar to a use case). The user story concerns itself with how the overall system solves a particular problem. It represents a part of the functionality of the overall system. A group of user stories is capable of describing the system as a whole. The developers refactor the previous code iteration to establish the design needed to implement the functionality.
During the Extreme Programming development life cycle, developers usually work in pairs. One developer writes the code for a particular feature, and the second developer reviews the code to ensure that it uses simple solutions and adheres to best design principles and coding practices.

Agile Methodology


Agile Methodology

Most software development life cycle methodologies are either iterative or follow a sequential model (as the waterfall model does). As software development becomes more complex, these models cannot efficiently adapt to the continuous and numerous changes that occur. Agile methodology was developed to respond to changes quickly and smoothly. Although the iterative methodologies tend to remove the disadvantage of sequential models, they still are based on the traditional waterfall approach. Agile methodology is a collection of values, principles, and practices that incorporates iterative development, test, and feedback into a new style of development. For an overview of agile methodology, see the Agile Modeling site athttp://www.agilemodeling.com/.
The key differences between agile and traditional methodologies are as follows:
  • Development is incremental rather than sequential. Software is developed in incremental, rapid cycles. This results in small, incremental releases, with each release building on previous functionality. Each release is thoroughly tested, which ensures that all issues are addressed in the next iteration.
  • People and interactions are emphasized, rather than processes and tools. Customers, developers, and testers constantly interact with each other. This interaction ensures that the tester is aware of the requirements for the features being developed during a particular iteration and can easily identify any discrepancy between the system and the requirements.
  • Working software is the priority rather than detailed documentation. Agile methodologies rely on face-to-face communication and collaboration, with people working in pairs. Because of the extensive communication with customers and among team members, the project does not need a comprehensive requirements document.
  • Customer collaboration is used, rather than contract negotiation. All agile projects include customers as a part of the team. When developers have questions about a requirement, they immediately get clarification from customers.
  • Responding to change is emphasized, rather than extensive planning. Extreme Programming does not preclude planning your project. However, it suggests changing the plan to accommodate any changes in assumptions for the plan, rather than stubbornly trying to follow the original plan.
Agile methodology has various derivate approaches, such as Extreme Programming, Dynamic Systems Development Method (DSDM), and SCRUM. Extreme Programming is one of the most widely used approaches.

Thursday, August 11, 2011

What is TDD?


The steps of test first design (TFD) are overviewed in the UML activity diagram of Figure 1.  The first step is to quickly add a test, basically just enough code to fail.  Next you run your tests, often the complete test suite although for sake of speed you may decide to run only a subset, to ensure that the new test does in fact fail.  You then update your functional code to make it pass the new tests.  The fourth step is to run your tests again.  If they fail you need to update your functional code and retest.  Once the tests pass the next step is to start over (you may first need to refactor any duplication out of your design as needed, turning TFD into TDD).TDD: A Practical Guide


Figure 1. The Steps of test-first design (TFD).

I like to describe TDD with this simple formula:
   TDD = Refactoring + TFD.
TDD completely turns traditional development around. When you first go to implement a new feature, the first question that you ask is whether the existing design is the best design possible that enables you to implement that functionality.  If so, you proceed via a TFD approach.  If not, you refactor it locally to change the portion of the design affected by the new feature, enabling you to add that feature as easy as possible.  As a result you will always be improving the quality of your design, thereby making it easier to work with in the future.
Instead of writing functional code first and then your testing code as an afterthought, if you write it at all, you instead write your test code before your functional code.  Furthermore, you do so in very small steps – one test and a small bit of corresponding functional code at a time.  A programmer taking a TDD approach refuses to write a new function until there is first a test that fails because that function isn’t present.  In fact, they refuse to add even a single line of code until a test exists for it.  Once the test is in place they then do the work required to ensure that the test suite now passes (your new code may break several existing tests as well as the new one).  This sounds simple in principle, but when you are first learning to take a TDD approach it proves require great discipline because it is easy to “slip” and write functional code without first writing a new test.  One of the advantages of pair programming is that your pair helps you to stay on track.