Procedural languages introduced functions for providing re-usability for a block of code. Object Oriented programming languages inherited the idea and allowed object behaviors to be defined in terms of methods. These methods are called. After doing some house keeping work, the runtime jumps to the callee and executes the code. After it is done execution, it brings the control back to the caller. This call scenario enables the use of try/catch and thread synchronization constructs for any subsequent calls. Based on this call scenario, the control has to come back to the caller after executing the callee. Programming languages also support other scenarios for executing a piece of code. We say that a catch block is executed and not called as we know that control will not go back to the point where exception was thrown, again, exceptions are thrown. There are other scenarios which might cause another scenario e.g. events are fired which cause all subsequent subscribed event handlers to be called.
In order to pass control back to the caller, the callee can explicitly use return statement. There is an implicit return statement at the end of a method with a void return type without an explicit return statement. For a method with a non-void return type, the return statement must be explicit.
Single Entry / Exit Points
Structured Programming suggests that we should only have one return path in a function. This would lead towards a single return statement per method. They are also often referred as exit points. Based on this idea, a method should always have a single entry & exit points. The single entry and exit points provides more readability to the code allowing it very easy to follow through the code and determining the intent and responsibility of the method.
Developers claim it to be bad coding style and coding risk. But it also makes it very difficult to refactor the code with multiple return statement specially when we need to extract some code into a new method from an existing method with convoluted code with multiple return statements. It is also a maintenance nightmare to touch such a code to fix any upcoming issue. Additionally, it is not easy to unit test such a code to cover all cases without the help of a code coverage tool used with your unit test in order to avoid false positives.
Based on this, it seems apparent that multiple return statements are really evil and we should be avoiding them when writing our code. Bob Martin recommended Boy Scout's principle for code changes [You should leave the code cleaner than you find it]. So this can be part of our cleanup exercise to change all methods with multiple return statements into single ones. This should cause sanity to prevail. This also allows us to add any cleanup code necessary before the only return statement in the method.
Arrow antipattern
Applying arrow pattern religiously leads us into another problem. In order to avoid multiple return statements we tend to add multiple if statements in a nested fashion. This gets worse if we have multiple parameters and we need to check for the input arguments for some preconditions. This situation is generally referred to as Arrow antipattern. The code appears as follows:
Arrow antipattern reduces readability because of increased right margins. It also increases complexity of the code by providing various code flow paths which makes unit testing a hell. This page discusses about arrow antipattern and possible refactoring to fix that [http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html]
Guard Clauses
Fowler recommends using guard clauses for all special cases. His recommendation is conditional behaviors in a method which doesn't have a very clear normal path of execution. These guard clauses can also be used for checking preconditions for a method. A failed precondition generally results in an exception.
Constructors and Dependency Injection
Object oriented languages provide constructors for instantiating a type. They are part of class' metadata and cannot be invoked like a regular method. Mark Seeman suggests constructor injection to be preferred choice in most cases. This requires all dependencies to be specified as constructor arguments.
Testing dependencies in a guard clause is necessary as these dependencies are preconditions for object's inner working. But we need to check for all of these dependencies cause missing any of them should fail the instantiation of type under consideration. In order to verify these guard clauses, we need unit tests. In the above case, we need two unit tests to verify these dependencies if we follow One Assert per Test rule. Increasing the number of dependencies might need more tests.
I have seen people getting more excited and checking the combination of these dependencies but that seems too much as there are generally unique guard clauses for each dependency. In the below code, we are trying to test the above construction logic. Here we are testing that setting any constructor's parameter to null should result in an exception. These tests are also very brittle as introducing a new dependency requires updating all of these tests.
Here we are using xUnit for unit testing. We are using Rhino Mocks for mocking the dependencies.
Code is a liability
Unit tests should follow DRY [Don't Repeat Yourself] principle of Extreme Programming. Their names should follow DAMP (Descriptive And Meaningful Phrases). Introducing any new type involves this arduous work of construction tests. Since we are not introducing a type just because we have fancy construction, but for the logic that it implements, putting effort for writing these tests takes this useful time away from logic testing.
Mark Seemann has provided AutoFixture.Idioms for such unit tests which tend to follow such common templates. This has a dependency on AutoFixture nuget package. Let's install these packages to our test project. We have also installed xUnit package as a unit testing library.
AutoFixture.Idioms provide GuardClauseAssertion to verify that an exception is thrown if a dependency is missing. In the following code we are trying to assert the guard clauses for all the dependencies for all the constructors.
But to test these guard clauses, it needs to pass the required dependencies as constructor arguments. But the dependencies cannot be instantiated as they are interface types. Running the above test fails with the following message:
AutoFixture has provided additional extension packages to support mocking libraries including Moq, FakeItEasy and RhinoMocks. Let's install the package which uses Rhino Mocks. Obviously this package has an additional dependency on Rhino Mocks. This package is called AutoFixture.AutoRhinoMocks.
After installing the above package we can add customization to the Fixture to support Rhino Mocks for mocking the required dependencies. The test would fail if there is a guard clause missing from any constructor for the specified type. This approach reduces the effort for unit testing the code required just for defensive code and we can concentrate on the real application logic.
Testing Guard Clauses for Methods
Methods can also have guard clauses to check for dependencies. We can use AutoFixture idioms to assert these clauses as well. Let' add an additional behavior to the IAuthenticationService method to support adding an authentication policy. We need to add the same method to the AuthenticationService implementation. The method just has one parameter of IAuthenticationPolicy type.
If we are missing the guard clause for null testing of the provided argument, the test would fail. It results in the following in your unit testing session. Here we are using resharper support for xUnit to run tests and show the results.
Adding an guard clause which results in an exception, would follow the expectation. It is shown as green in the session. The test would pass. It is shown in the testing session as follows:
In order to run the above tests, we needed to add a few nuget packages. The names and dependencies of these packages can be checked using Package Visualizer.
Why is this a great achievement?
Just to be able to run this test is a big achievement for software design and development world. Let me tell you what is happening here. Basically this test is a combination of a test runner with a different assertion library with mocking support from another provider. Here we are using XUnit for running our tests. Auto Fixture Idioms are helping us asserting the guard clause checks. In order to create mocks, AutoFixture is using Rhino Mocks. So this has test runner, assertion and auto mocking libraries from different providers. Together they are able to help us achieving this miracle. Isn't this great?
Download Code
Friday, May 17, 2013
Arrows, Guard Clauses & Assertions using AutoFixture.Idioms
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment