Click here to Skip to main content
Click here to Skip to main content

Advanced Unit Test, Part V - Unit Test Patterns

By , 3 Mar 2004
 

Previous articles in the series:

What's New?

Added a section on Presentation Layer Test Patterns.

Join The Advanced Unit Testing Project!

We're looking for experienced C# developers that can dedicate quality time to a large list of to-do features to help make Visual Test Studio the leader in unit test open-source efforts.  Are you interested in working with cutting edge technology and being a leader in a rapidly growing engineering practice?  Would you like to become known in the unit test field as helping to architect and develop Visual Test Studio?  Then sign up at http://aut.tigris.org/ and contact Marc for information on how you can contribute!

Contents

Introduction

The idea of unit testing seems to always evoke a strong reaction in people.  For those that buy into the concept, they have unanimously stated that good unit tests are difficult to write, and some question whether the tests they have written were really worth it while others rave about their effectiveness.  On the other hand, there is also a large community that guffaws at the idea of unit testing, especially the concept that "the code is good when it passes the unit tests".  When all the hoopla dies down, unit testing may one day be relegated to the dusty shelf of "yet another programmer tool".  If this fate is to be changed, unit testing has to be embraced by both the community and the tool developers.  The next version of Microsoft's Visual Studio will include tools to automate refactoring.  It seems obvious to me that tools that automate unit test generation would not only address some of the issues concerning maintenance and cost, but would also introduce the concept to a much wider audience.

However, to achieve this acceptance, unit testing must be formalized so that it becomes a real engineering discipline rather than an ad hoc approach that relies on the dubious capabilities of the programmer.  After all, the unit test is supposed to test the code that the programmer writes.  If the programmer writes bad code to begin with, how can you expect anything of better quality in the tests?  Of even more concern is the concept that the unit test should be written first, before the code that is to be tested.  To a certain extent, this implies that not only does the programmer have to consider what the code will do, he/she has to consider how the code is designed.  Both drive the interface.  This is why many people balk at the idea of writing the unit test first--it places them in the uncomfortable position of having to do up front design work without consciously recognizing that this what they are doing.

So, we are faced with a double edged sword.  First, there is no formal unit test engineering discipline established in the community that provides a guide to the programmer and works to ensure some level of unit test quality.  Second, the prerequisite that the design has to be somewhat formalized before any tests can be written causes difficulty for many programmers because they either don't have formal design experience or simply don't like up front design work.  Aggravating this situation is the idea that up front design work can be replaced under the guise of "refactoring".

In order to blunt this sword, two things are needed--a formalization of unit testing by establishing unit test patterns, and the early adoption of object oriented design patterns in the developing application to specifically target the needs of unit testing.  This article will paint a picture of this two pronged solution with some very large brush strokes.  The intention is to whet your appetite and hopefully begin a dialog amongst yourselves that will lead to a more formal unit test engineering process, similar to object oriented design, design patterns, and refactoring.

As you read this article, keep in mind that one of the goals is a tool suite that can be used to automatically generate unit tests, both as a reverse and forward engineering process.  With the latter, it should be possible to generate the method stubs for the code under test.  After all, one of the benefits of unit testing is that it provides the implementer with some documentation as to the expected structure and behavior of the code under test.  Also, to keep this article in the general reader category, there are no code examples.

Patterns

The patterns that I have identified so far can be loosely categorized as:

  • pass/fail patterns
  • collection management patterns
  • data driven patterns
  • performance patterns
  • process patterns
  • simulation patterns
  • multithreading patterns
  • stress test patterns

Again, let me emphasize that these are broad brush strokes.  From my research, this appears to be quite new territory.

Pass/Fail Patterns

These patterns are your first line of defense (or attack, depending on your perspective) to guarantee good code.  But be warned, they are deceptive in what they tell you about the code.

The Simple-Test Pattern

Pass/fail unit tests are the simplest pattern and the pattern that most concerns me regarding the effectiveness of a unit test.  When a unit test passes a simple test, all it does is tell me that the code under test will work if I give it exactly the same input as the unit test.  A unit test that exercises an error trap is similar--it only tells me that, given the same condition as the unit test, the code will correctly trap the error.  In both cases, I have no confidence that the code will work correctly with any other set of conditions, nor that it will correctly trap errors under any other error conditions.  This really just basic logic.  However, on these grounds you can hear a lot of people shouting "it passed!" as all the nodes on the unit test tree turn green.

The Code-Path Pattern

The Simple-Test pattern typifies what I call "black box testing".  Without inspecting the code, that's about all you can do--write educated guesses as to what the code under test might encounter, both as success cases and failure cases, and test for those guesses.  A better test ensures that at least all the code paths are exercised.  This is part of "white box testing"--knowing the inside workings of the code being tested.  Here the priority is not to set up the conditions to test for pass/fail, but rather to set up conditions that test the code paths.  The results are then compared to the expected output for the given code path.  But now we have a problem--how can you do white box testing (testing the code paths) when the code hasn't been written?  Here we are immediately faced with the "design before you code" edge of that sword.  The discipline here, and the benefit of unit testing by enforcing some up front design, is that the unit test can test for code paths that the implementer may not typically consider.  Furthermore, the unit test documents precisely what the code path is expected to do.  Conversely, discipline is needed during implementation when it is discovered that there are code paths that the unit test did not foresee--time to fix the unit test!

The Parameter-Range Pattern

Still, the above test, while improving on the Simple-Test pattern, does nothing to convince me that the code handles a variety of pass/fail conditions.  In order to do this, the code should really be tested using a range of conditions.  The Parameter-Range pattern does this by feeding the Code-Path pattern with more than a single parameter set.  Now I am finally beginning to have confidence that the code under test can actually work in a variety of environments and conditions. 

Data Driven Test Patterns

Constructing Parameter-Range unit tests is doable for certain kinds of testing, but it becomes inefficient and complicated to test at a piece of code with a complex set of permutations generated by the unit test itself.  The data driven test patterns reduce this complexity by separating the test data from the test.  The test data can now be generated (which in itself might be a time consuming task) and modified independent of the test.

The Simple-Test-Data Pattern

In the simplest case, a set of test data is iterated through to test the code and a straightforward result (either pass or fail) is expected.  Computing the result can be done in the unit test itself or can be supplied with the data set.  Variances in the result are not permitted.  Examples of this kind of of Simple-Test-Data pattern include checksum calculations, mathematical algorithms, and simple business math calculations.  More complex examples include encryption algorithms and lossless encoding or compression algorithms.

The Data-Transformation-Test Pattern

The Data-Transformation-Test pattern works with data in which a qualitative measure of the result must be performed.  This is typically applied to transformation algorithms such as lossy compression.  In this case, for example, the unit test might want to measure the performance of the algorithm with regard to the compression rate vs. the data loss.  The unit test may also need to verify that the data can be translated back into something that resembles the input data within some tolerance.  There are other applications for this kind of unit test--a rounding algorithm that favors the merchant rather than the customer is a simple example.  Another example is precision.  Precision occurs frequently in business--the calculation of taxes, interesting, percentages, etc., all of which ultimately must be rounded to the penny or dollar but can have dramatic effects on the resulting value if precision is not managed correctly throughout the calculation.

Data Transaction Patterns

Data transaction patterns are a start at embracing the issues of data persistence and communication.  More on this topic is discussed under "Simulation Patterns".  Also, these patterns intentionally omit stress testing, for example, loading on the server.  This will be discussed under "Stress-Test Patterns".

The Simple-Data-I/O Pattern

This is a simple data transaction pattern, doing little more than verifying the read/write functions of the service.  It may be coupled with the Simple-Test-Data pattern so that a set of data can be handed to the service and read back, making the transaction tests a little bit more robust.

The Constraint-Data Pattern

The Constraint-Data pattern adds robustness to the Simple-Data-I/O pattern by testing more aspects of the service and any rules that the service may incorporate.  Constraints typically include:

  • can be null
  • must be unique
  • default value
  • foreign key relationship
  • cascade on update
  • cascade on delete

As the diagram illustrates, these constraints are modeled after those typically found in a database service and are "write" oriented.  This unit test is really oriented in verifying the service implementation itself, whether a DB schema, web service, or other model that uses constraints to improve the integrity of the data.

The Rollback Pattern

The rollback pattern is an adjunct to the other transaction testing patterns.  While unit tests are supposed to be executed without regard to order, this poses a problem when working with a database or other persistent storage service.  One unit test may alter the dataset causing another unit test to inappropriately fail.  Most transactional unit tests should incorporate the ability to rollback the dataset to a known state.  This may also require setting the dataset into a known state at the beginning of the unit test.  For performance reasons, it is probably better to configure the dataset to a known state at the beginning of the test suite rather than in each test and use the service's rollback function to restore that state for each test (assuming the service provides rollback capability).

Collection Management Patterns

A lot of what applications do is manage collections of information.  While there are a variety of collections available to the programmer, it is important to verify (and thus document) that the code is using the correct collection.  This affects ordering and constraints.

The Collection-Order Pattern

This is a simple pattern that verifies the expected results when given an unordered list.  The test validates that the result is as expected:

  • unordered
  • ordered
  • same sequence as input

This provides the implementer with crucial information as to how the container is expected to manage the collection.

The Enumeration Pattern

This pattern verifies issues of enumeration, or collection traversal.  For example, a collection may need to be traversed forwards and backwards.  This is an important test to perform when collections are non-linear, for example a collection of tree nodes.  Edge conditions are also important to test--what happens when the collection is enumerated past the first or last item in the collection?

The Collection-Constraint Pattern

This pattern verifies that the container handles constraint violations: null values and inserting duplicate keys.  This pattern typically applies only to key-value pair collections.

The Collection-Indexing Pattern

The indexing tests verify and document the indexing methods that the collection container must support--by index and/or by key.  In addition, they verify that update and delete transactions that utilize indexing are working properly and are protected against missing indexes.

Performance Patterns

Unit testing should not just be concerned with function but also with form.  How efficiently does the code under test perform its function?  How fast?  How much memory does it use?  Does it trade off data insertion for data retrieval effectively?  Does it free up resources correctly?  These are all things that are under the purview of unit testing.  By including performance patterns in the unit test, the implementer has a goal to reach, which results in better code, a better application, and a happier customer.

The Performance-Test Pattern

The basic types of performance that can be measured are:

  • Memory usage (physical, cache, virtual)
  • Resource (handle) utilization
  • Disk utilization (physical, cache)
  • Algorithm Performance (insertion, retrieval, indexing, and operation)

Note that some languages and operating systems make this information difficult to retrieve.  For example, the C# language with its garbage collection is rather difficult to work with in regards to measuring memory utilization.  Also, in order to achieve meaningful metrics, this pattern must often be used in conjunction with the Simple-Test-Data pattern so that the metric can measure an entire dataset.  Note that just-in-time compilation makes performance measurements difficult, as do environments that are naturally unstable, most notably networks.  I discuss the issue of performance and memory instrumentation in my fourth article in a series on advanced unit testing found at http://www.codeproject.com/csharp/autp4.asp.

Process Patterns

Unit testing is intended to test, well, units...the basic functions of the application.  It can be argued that testing processes should be relegated to the acceptance test procedures, however I don't buy into this argument.  A process is just a different type of unit.  Testing processes with a unit tester provide the same advantages as other unit testing--it documents the way the process is intended to work and the unit tester can aid the implementer by also testing the process out of sequence, rapidly identifying potential user interface issues as well.  The term "process" also includes state transitions and business rules, both of which must be validated.

The Process-Sequence Pattern

This pattern verifies the expected behavior when the code is performed in sequence, and it validates that problems when code is executed out of sequence are properly trapped.  The Process-Sequence pattern also applies to the Data-Transaction pattern--rather than forcing a rollback, resetting the dataset, or loading in a completely new dataset, a process can build on the work of the previous step, improving performance and maintainability of the unit test structure.

The Process-State Pattern

The concept of state cannot be decoupled from that of process.  The whole point of managing state is so that the process can transition smoothly from one state to another, performing any desired activity.  Especially in "stateless" systems such as web applications, the concept of state (as in the state of the session) is important to test.  To accomplish this without a complicated client-server setup and manual actions requires a unit tester that can understand states and allowable transitions and possibly also work with mock objects to simulate complicated client-server environments.

The Process-Rule Pattern

This test is similar to the Code-Path pattern--the intention is to verify each business rule in the system.  To implement such a test, business rules really need to be properly decoupled from surrounding code--they cannot be embedded in the presentation or data access layers.  As I state elsewhere, this is simply good coding, but I'm constantly amazed at how much code I come across that violates these simple guidelines, resulting in code that is very difficult to test in discrete units.  Note that here is another benefit of unit testing--it enforces a high level of modularity and decoupling.

Simulation Patterns

Data transactions are difficult to test because they often require a preset configuration, an open connection, and/or an online device (to name a few).  Mock objects can come to the rescue by simulating the database, web service, user event, connection, and/or hardware with which the code is transacting.  Mock objects also have the ability to create failure conditions that are very difficult to reproduce in the real world--a lossy connection, a slow server, a failed network hub, etc.  However, to properly use mock objects the code must make use of certain factory patterns to instantiate the correct instance--either the real thing or the simulation.  All too often I have seen code that creates a database connection and fires off an SQL statement to a database, all embedded in the presentation or business layer!  This kind of code makes it impossible to simulate without all the supporting systems--a preconfigured database, a database server, a connection to the database, etc.  Furthermore, testing the result of the data transaction requires another transaction, creating another failure point.  As much as possible, a unit test should not in itself be subject to failures outside of the code it is trying to test.

Mock-Object Pattern

In order to properly use mock objects, a factory pattern must be used to instantiate the service connection, and a base class must be used so that all interactions with the service can be managed using virtual methods.  (Yes, alternatively, Aspect Oriented Programming practices can be used to establish a pointcut, but AOP is not available in many languages).  The basic model is this:

To achieve this construct, a certain amount of foresight and discipline is needed in the coding process.  Classes need to be abstracted, objects must be constructed in factories rather than directly instantiated in code, facades and bridges need to be used to support abstraction, and data transactions need to be extracted from the presentation and business layers.  These are good programming practices to begin with and result in a more flexible and modular implementation.  The flexibility to simulate and test complicated transactions and failure conditions gains a further advantage to the programmer when mock objects are used.

The Service-Simulation Pattern

This test simulates the connection and I/O methods of a service.  In addition to simulating an existing service, this pattern is useful when developing large applications in which functional pieces are yet to be implemented.

The Bit-Error-Simulation Pattern

I have only used this pattern in limited applications such as simulating bit errors induced by rain-fade in satellite communications.  However, it is important to at least consider where errors are going to be handled in the data stream--are they handled by the transport layer or by higher level code?  If you're writing a transport layer, then this is a very relevant test pattern.

The Component-Simulation Pattern

In this pattern, the mock object simulates a component failure, such as a network cable, hub, or other device.  After a suitable time, the mock object can do a variety of things:

  • throw an exception
  • return incomplete or completely missing data
  • return a "timeout' error

Again, this unit test documents that the code under test needs to handle these conditions.

Multithreading Patterns

Unit testing multithreaded applications is probably one of the most difficult things to do because you have to set up a condition that by its very nature is intended to be asynchronous and therefore non-deterministic.  This topic is probably a major article in itself, so I will provide only a very generic pattern here.  Furthermore, to perform many threading tests correctly, the unit tester application must itself execute tests as separate threads so that the unit tester isn't disabled when one thread ends up in a wait state.

The Signalled Pattern

This test verifies that a worker thread eventually signals the main thread or another worker thread, which then completes its task.  This may be dependent on other services (another good use of mock objects) and the data on which both threads are operating, thus involving other test patterns as well.

The Deadlock-Resolution Pattern

This test, which is probably very complicated to establish because it requires a very thorough understanding of the worker threads, verifies that deadlocks are resolved.

Stress-Test Patterns

Most applications are tested in ideal environments--the programmer is using a fast machine with little network traffic, using small datasets.  The real world is very different.  Before something completely breaks, the application may suffer degradation and respond poorly or with errors to the user.  Unit tests that verify the code's performance under stress should be met with equal fervor (if not more) than unit tests in an ideal environment.

The Bulk-Data-Stress-Test Pattern

This test is designed to validate the performance of data manipulation when working with large data sets.  These tests will often reveal inefficiencies in insertion, access, and deletion processes which are typically corrected by reviewing the indexing, constraints, and structure of the data model, including whether code is should be run on the client or the server.

The Resource-Stress-Test Pattern

Resource consumption stress testing depends on features of the operating system and may be served better by using mock objects.  If the operating system supports simulating low memory, low disk space, and other resources, then a simple test can be performed.  Otherwise, mock objects must be used to simulate the response of the operating system under a low resource condition.

The Loading-Test Pattern

This test measures the behavior of the code when another machine, application, or thread is loading the "system", for example high CPU usage or network traffic.  This is a simulation only (which does not use mock objects) and therefore is of dubious value.  Ideally, a unit test that is intended to simulate a high volume of network traffic would create a thread to do just that--inject packets onto the network.

Presentation Layer Patterns

One of the most challenging aspects of unit testing is verifying that information is getting to the user right at the presentation layer itself and that the internal workings of the application are correctly setting presentation layer state.  Often, presentation layers are entangled with business objects, data objects, and control logic.  If you're planning on unit testing the presentation layer, you have to realize that a clean separation of concerns is mandatory.  Part of the solution involves developing an appropriate Model-View-Controller (MVC) architecture.  The MVC architecture provides a means to develop good design practices when working with the presentation layer.  However, it is easily abused.  A certain amount of discipline is required to ensure that you are, in fact, implementing the MVC architecture correctly, rather than just in word alone.

Sun Microsystems has a webpage which I consider is the gospel for the MVC archicture: http://java.sun.com/blueprints/patterns/MVC-detailed.html.  To summarize the MVC pattern here:

It is vital that events are used for model notification changes and user gestures, such as clicking on a button.  If you don't use events, the model breaks because you can't easily exchange the view to adjust the presentation to the particular presentation layer requirement.  Furthermore, without events, objects become entangled.  Also, events, such as managed by an event pool, allow for instrumentation and ease debugging.  The only exception to this model that I have found in practice is that on occasion, a state change in the model might be captured by an event in the controller rather than the view.  Some model changes, such as user authorization, are view-less but end up affecting other aspects of the controller.

The View-State Test Pattern

This test verifies that for a change in the model state, the view changes state appropriately.

This test exercises only half of the MVC pattern--the model event notifications to the view, and the view management of those events in terms of affects on the presentation layer content and state.  The controller is not a factor in this test pattern.

The Model-State Test Pattern

Once we have verified application's performance with the View-State Pattern, we can progress to a more complicated one.  In this pattern, the unit test simulates user gestures by setting state and content directly in the presentation layer, and if necessary, invoking a state change event such as "KeyUp", "Click", etc.

As diagrammed above, the unit test verifies that the model state has changed appropriately and that the expected events fired.  In addition, the view's events can be hooked and verified to fire correctly for the simulated user gesture.  This test may require some setup on the model itself, and treats the controller as a black box, however model state can be inspected to determine whether the controller is managing the model state appropriately.

Conclusion

This article has described 24 test patterns that hopefully bring the technique of unit testing closer to a more formal engineering discipline.  When writing unit tests, reviewing these patterns should help in identifying the kind of unit test to write, and the usefulness of that unit test.  It also allows the developer to choose how detailed the unit tests need to be--not every piece of code needs to be stress tested, nor is it cost effective to do so.

As you can see from this article, we desperately need some tools that generate unit tests automatically.  I'm not much of an advocate of code generates, but I can see that unit testing would really benefit from code generation.  It would all but eliminate the arguments against unit testing based on cost and effectiveness, and could also be used as an application generating tool--given information on the unit test, the code generator can also create the application code classes, structure, and stubs.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Marc Clifton
United States United States
Member
Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.
 
Marc lives in Philmont, NY.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membermanoj kumar choubey21 Mar '13 - 22:53 
Nice
QuestionIs there any Rating more than 5memberalbert arul prakash7 Dec '12 - 18:03 
Thanks for such a wonderful article. Thanks buddy
Albert


Have a date for free

GeneralMy vote of 5memberB.Farivar8 Oct '12 - 21:31 
Good
GeneralGreat articlemembermaguschen28 Jun '09 - 22:58 
It describe so many test patterns in detail
Thank you very much.
 
http://magustest.com/
GeneralThank a lotmemberjosemaocu22 Aug '08 - 4:24 
So long i was searching for anything similar.
 
Thanks & Congratulations
Kind Regards.
tutoriales photoshop
GeneralRe: Thank a lotmemberJorge Bay Gondra19 Sep '08 - 0:44 
Nice!
 
Regards,
Jorgebg
 
Diseño web
Generalarticlemembervnexster25 Jun '07 - 20:52 
ii bun
Questionwhere is disp.xls , why reverse testing xml utils fails ?membersandi_ro13 Oct '06 - 21:37 
Hi,
 
I tried the sources from your site still there is a problem with them there is no disp.xls so a FileNotfound exception pops up.
 
It would be nice to have it.
 
Also noticed that reverse tests for xml utilities fails so I wonder if this is ok or not . I expected them to pass as long tey are designed for AUT and are included there . For such a nice article I was expecting a finished /complete AUT, or at least some comments/notes or a page near download link ?

 
Signed: Anonymous Smile | :)

Generalquestions discussion book clubsussAnonymous7 Mar '05 - 13:31 
questions discussion book club
Generalbuilt on proprietary technology? i will pass on it.sussSleepyJoe4 Mar '05 - 13:50 
You presented this topic very well. Good work! This is definitely a 5 out of 5 rating. However, why be limited to proprietary language designed for a specific operating system?
 
As far as testing patterns, I only use a few of the patterns you listed in the following percents: Pass/Fail=75%, Multi-threading=20%, Data Driven=5%. And, the multi-threading tests as well as the data driven tests are just variations of the pass/fail test. So, they are really all pass/fail. The code i use to repeat threading and data driven test patterns is just block copied. I never took the time to make a reusable framework, since the code is rather simple and small such that copying is no big deal.
 
Another thing is that unit tests serve as example code, so as much as possible, tests are concrete examples that can be cut and pasted into project code. I would avoid hiding things like initialization, iteration, and life cycle in some sort of testing framework because that would obfuscate the code. One of my primary motivations as I am writing test cases, is to present simple "hello world" scenarios completely contained within one function call. I prefer these test cases for documentation purpose over paragraphs of comments embedded in header files, and even over doxygen HTML files.
 
For an open source project to truly be useful, stick to ANSI C++, and platform independent code. I like unit testing, and find that it makes portability easier. I can develop on one platform, and run unit tests on the other platforms (Windows versions, Linux versions, BSD, Mac).
 
A fancy GUI is always kinda cool, but totally unnecessary for unit testing in my opinion. My tests print a dot '.' for each success, and display a file/line/message for errors. That's all i need.
Generalcreate a unit test data toolmemberRedSunBeer25 Jan '05 - 3:58 
The article really widened my horizons. ITs gr8. I also read the other reviews about the hassles of writing, updating and executing unit tests at least for the normal developer. Which got me thinking Sleepy | :zzz: ......
 
Why not have a tool that actually creates test data. Based upon the data type of the attribute, parameter, return values or method signature the tool would create the data for testing.
 
OR
The 'stuff' to tested should be accurately described so that the right test data is generated. For example in visual studio .net we write comments using the "///" and <> symbols for each method, property which is stored internally by visual studio. If the test data tool could read this data it would know what kind of data is to be generated. This may require some extra tags which inform the system what kind of data is to be passed. So let's say that we have a tag called <validdata> alphanumeric <validdata/>. This word 'alphnumeric' here woud have a special meaning for the tool based upon which it would know what valid and invalid data to generate.
 
OR
perhaps runtime attributes (similar to nunit) could point to a (re)source which helps the tool understand how to create the test data.
 
OR
am I just wasting time here.Hmmm | :|
 
Rose | [Rose]
GeneralTestability PatternsmemberStephan Meyn28 Aug '04 - 14:21 
Great article - I'll pass it on to my organisation's practice group as suggested reading.
I think this needs another pattern called testability. This refers to the way Systems Under Test (SUT) should be written to make them testable. This includes:
  1. separating distinct functionality into separate functions
  2. Diagnostic patterns
  3. Inspection patterns
  4. exposing otherwise private functions available to the test harness
  5. mock plugs
  6. state indicators
  7. etc...

GeneralSecurity Test PatternssussAnonymous4 Mar '04 - 23:29 
The following test patterns should be added for security purposes
 
Access Control (includes deny as default and tests for least privilege
Impersonation (check for failed impersonation)
Stack Overruns
Heap Overruns
Buffer Overflows
Buffer Underflows
Format Strings (things like "%s", submitted in string
Name-Squatting
Cross Site Scripting
SQL Injection
OS Command Injection
Path Traversal
Meta Characters
NULL Bytes
Canonicalization - case sensitivity
Canonicalization - unicode
Canonicalization - url encoding
Session Replay
Questionlevel of abstraction?sussBrad Williams25 Jan '04 - 15:41 
Thanks for writing this article Marc (even the whole series), it is quite thought provoking. This one is especially bold, so my hat's off to you.
 
I must admit to feeling confused about a couple things. For one, I'm not sure that the most useful unit tests can be captured by a pattern beyond the Simple-Test pattern. (Actually in a sense don't all unit tests fall into the Simple-Test pattern??) Second, I think these patterns are at different levels of abstraction -- which is fine, but I had to realize that to get more comfortable with them.
 
In my mind, your unit tests should test/assert that a class (or component etc) performs the way in which you need it to perform. Because of this the form of your unit test is dependent on how your class actually works. If a class is enumerable and transactional, then it will take unit tests which test those qualities. In this sense I see the motivation for the "Data Transaction Patterns" and "Collection Management Patterns" and "Constraint Data" patterns etc. So for any common implementation idioms, there is going to be such a corresponding unit testing "pattern." For example, does your class support casting operations? Maybe that needs a unit testing pattern. Do groups of your classes have ways to traverse between them? Maybe those need an object traversal unit testing pattern. Thinking about common behaviors that components support, there are probably many more such unit testing patterns for them.
 
But then there are the peculiar behaviors of the classes and components in a system, and to test these is exactly where I think none of those patterns is going to help you. I may want to unit test my fraction class by creating an object with numerator 3 and denominator 4, then assure that this object correctly casts to a 0.75 float. Which pattern is this? I guess it is just the Simple-Test pattern. Now from reading the article I might think that such tests are not very useful, but aren't many extremely useful tests of the particular behaviors of your classes going to be of this variety? Such tests do not follow any interesting pattern (i.e., they are not generalizable), because the nature of the test is a reflection of the peculiar design of one class, which is reflecting a particular requirement. I think some of my most useful unit tests (useful in terms of both helping me tweak the class's design, and in finding bugs created by refactors) have been of this variety. Or to put it more strongly, I think if one's unit tests do not contain such pattern-defying, application specific tests, then they probably aren't doing you much good.
 
Many of the other patterns you describe seem to be at a higher level of abstraction. They are not "test this programming idiom" (such as collection functionality or db transactionality), but (sometimes) "test in this way", such as the Simple-Test-Data pattern or the Simulation Patterns. For me it is clarifying to segregate your patterns on this basis.
 
Brad Williams

GeneralPunishmentsussAndrew T. Finnell17 Jan '04 - 10:04 

First and formost I write unit tests for my code. Why? Because I get that warm fuzzy when everything passes. Does that mean my code is without flaws? No, I dont think code will ever be without flaws until we get to the Star Trek level of programming (Just hit that button and you've reconfigured the shields to emmit a deadly beam). However I do believe that I have caught many bugs I've introduced into the system with my unit tests saving me invaluable time.
 
In one of the mentioned articles someone stated that Unit testing is a maintenance problem when refactoring is concerned. I suppose that is one way to look at it. However, imagine you change the subsystem of your project consisting of 10,000 lines of code. Now because you the developer dont believe there has been enough time and money allocated to testing havent done much QA yourself. Do you really feel more comfortable that you didnt have to change all that unit test code? Now all the changes have been implemented you've found that half the system doesnt work anymore. Where do you begin? You've spent the last 3 hours getting the code built, the machine reconfigured and installing the software just to find out most of it doesn't work. Dont think this can happen? I've been at companies where it happened weekly. The reason? "We dont have time to write the unit tests." was the anwser given. From a logical standpoint it doesn't make any sense. It's very similar to people that speed down the roads thinking it will get them faster, only to be stuck at the next stop light for 5 minutes while all the traffic you flew by catches up to you. Where as you could have plotted a shorter route with less stop lights which have been much easier then being fustrated at the end because nothing worked. One way or another you will end up spending more time and money for code that isnt tested.
 
The principal behind automated unit testing is the 'automated part'. The computer does the testing. While you did write the tests, the computer will ensure that the test is run the same way every time. QA with people is at best haphazerdous. How do you ensure that the QA person is going to test version 3.0 of your product the same way as the 3.1 version? If you can't ensure this then the previous tests are meaningless when the new version is released, yet we are somehow confident that the product didnt change _that much_.
 
Some also believe that unit testing can be used to design the interface and contract of a unit with the test itself without first writing the underlying code. Do you ever sit there and think about how your new class is going to work? Or what it's interface should look like? You ever find yourself imaging what it would be like to use the new class. You may not realize it but you were already doing the tests first. You are doing them in your head. Instead of sitting back and visualizing how the class will act, write it down in a form of a unit test. Then it will be captured. While you are writing the test you will more than likely find that you need to change some aspects of your interface to make it more user friendly and be more autonomous.
 
The fundamental problem with unit testing is the ease of use. For some that are in the spirit they can bypass the tediousness of writing the tests. Others give up because it distracts them from what they really want to do.
 
To know how fun and usefull writing these test can be, download Eclipse and use the built-in JUnit functionality. I believe this to be the best integrated unit testing framework as of yet. Having to run a 3rd party utility outside of your beloved notpad or IDE is not something anyone looks forward too. I believe the people of the Visual Studio (btw I love Visual Studio) world will soon find the place for unit testings in their lives when there is a more cohesive unit testing framework built into there favorite IDE.
 
Imagine if you were punished for writing buggy code. You wrote a piece of software that crashed and corrupted the user's data files and you were sentenced to jail for 5 years. I bet you would be more careful of how you test your code. This is what certified Engineer's face when they sign the Engineer's oath. They are legally obligated to build safe and working products whether it be brigdes, houses and the like. This field more often then not rewards developers for building buggy code. Really, think about it. You are hired to build a product for a company, once completed, you are continually paid to 'fix' the product and make it better. Bugs are taken for granted in a product. The idea subconsiously is to find the right mixture of bugs and working code so that you aren't fired, then it's a golden road to continually fixing your own code and getting paid for it. How about that?
 

 
-
Andrew T Finnell
Active Solutions LLC
andrew@activesol.net
GeneralRe: PunishmentmemberStephen Owens26 Jan '04 - 15:56 
Andrew,
 
I really agree with you about the benefits of solid IDE integration. As you say, Eclipse is fantastic! I've been working on both a large C++/COM project and a Java server side web system over the last few months. I can't get over how different my approach is to both projects.
 
I believe in the value of unit tests, and I push the envelope of completeness on the Java side. In C++ I still believe, I use CppUnit to try to get there, but the pain threshold remains just a little too high. It has to become part of the basic development flow, like the edit/compile/crash/debug/crash/debug/crash/debug cycle is.
 
In Java, with proper unit tests in place, I find the debugger sitting idle most of the time. In C++ it's in use far more frequently. That's partly a language difference, but it's also largely a stylistic difference brought on by the ease of unit testing in the Java/Eclipse environment.
 

 
Stephen Owens
Corner Software
GeneralRe: PunishmentmemberDaniel Turini11 Feb '04 - 23:06 
Andrew T. Finnell wrote:
Imagine if you were punished for writing buggy code. You wrote a piece of software that crashed and corrupted the user's data files and you were sentenced to jail for 5 years. (...) How about that?
Great. Now you just need to find a legal definition for bug.

 
Perl combines all the worst aspects of C and Lisp: a billion different sublanguages in one monolithic executable. It combines the power of C with the readability of PostScript. -- Jamie Zawinski
GeneralRe: Punishmentmemberafinnell12 Feb '04 - 7:52 
He he, yeah that would probably keep you out of trouble for years to come.
 
-
Andrew T Finnell
Active Solutions LLC
andrew@activesol.net
GeneralDeclarative programmingmemberMatt Gullett17 Jan '04 - 7:32 
I'm all for better testing and defined testing processes. I'm the first to admit that I don't do enough myself.
 
We in the SD business have a real problem, though. Management and customers rarely understand the importance of testing (from a time and money perspective) at least until something goes wrong. Developers are also doing a poor job (in general) of delivering well tested applications. Some developers will say that if a customer is not willing to pay for testing, they won't do business with them. That's fine when working in a sellers market, and especially when working with larger clients, but when you're in a buyers market or dealing with mostly small firms, this is a serious problem.
 
In my mind, what is needed, is a much better development platform, better devlopment practices and less testing. The reality is that much of the testing methodologies being employed cannot identify problems in a real world situation, especially when working with vastly distributed systems, web applications, etc. I am not saying testing is bad, quite the contrary, but I believe that testing should lead to better development and less testing, not the same development and more testing and more seemless testing.
 
Many of the tests are targeted at testing boundary conditions, ranges, null handling, etc. In my mind all of this testing should be dealt with completely through declarative specifications within and without the code. As an example, consider the function protoype below (C++ style).
 
int ComputeDistance(LPCTSTR lpszZipCode1, LPCTSTR lpszZipCode2);
 
This is a very simple function, but it leaves open to guess lots of details. First of all, is the return value in miles, KM, meters???? Second, can lpszZipCode1 or 2 be NULL. A better way to write this is by providing actual class types to accomodate the data passed and returned.
 
DistanceInMiles ComputeDistance(ZipCode ZipCode1, ZipCode ZipCode2);
 
This is better, but puts a burden on the developer to build lots of tiny classes. Another way this could be done is declaratively:
 
int ComputeDistance(LPCTSTR lpszZipCode1, LPCTSTR lpszZipCode2)
  :: return is Distance, Miles, Not Nullable, Positive or Zero, 
  :: lpszZipCode1 is 5 digits, numeric, Not Nullable
  :: lpszZipCode2 is 5 digits, numeric, Not Nullable
 
By declaring the meaning of parameters and return types (and other details if desired), a runtime can test inputs/outputs and throw exceptions before the function is executed. Add this to runtime automated instrumentation and logging, automated test tools and many testing problems are resolved. A validator could be written to interpert declarations for validity, possibly by comparing to known norms, etc.
 
I would add, that the second example I gave should also be doable, because I would be able to wrap the declarative constratints into a reusable class. Some of this can be done with templates and generic programming, but not all of it. Eifel supports a form of what I am talking about, design-by-contract, but I don't know all the details of how it works.
 
Obvoiusly, declarative programming does not solve every problem, far from it. BUT, it is a progressive RESULT of testing, instead of just progressing testing.
GeneralRe: Declarative programmingmemberStephan Meyn28 Aug '04 - 14:16 
Matt Gullett wrote:
Obvoiusly, declarative programming does not solve every problem, far from it. BUT, it is a progressive RESULT of testing, instead of just progressing testing.
 
That is true and certainly helpful. But you move the problem. In declarative programming you then need to test the declarations. Remember Ariane?
GeneralRe: Declarative programmingprotectorMarc Clifton28 Aug '04 - 15:42 
Stephan Meyn wrote:
In declarative programming you then need to test the declarations.
 
Indeed you do. MyXaml Lint[^]
 
Marc
GeneralGive Me a break!, is this really practical (interested in feedback)sussKentr7 Jan '04 - 1:25 
First of all, I want to thank Marc for doing an excellent job on this article. This is one of many articles he has written that are must reads for any good software developer. What I like most about Marc's articles is that he usually comes up with some new ideas that are worthwhile and thought provoking.
 
I would like to think of these "Test Patterns" more like "Best Practices" in our testing efforts. Like many of the popular design patterns, we read about these patterns and realize that we have been using them without even realizing it. We just needed someone smart enough (like Marc) to come along to describe it, illustrate it, and attach a name to it. As I was reading this article, I was saying to myself "ooohhhh yeeeeaaaa, I have used this pattern in my testing". Did any of you have this same experience?
 
As I was reading about all these test patterns that I probably should be using (by the way Marc, thanks for making feel guilty about not testing like I should), I asked myself the following question over and over again "which of these test patterns are an absolute must in my development efforts". I wish I could do them all, but I just don't have time (sound familiar); so I am curious, how many of these test patterns are developers using. Which of these test patterns are absolutely essential to the success of a software development project?
 
Last but not least, what would it take to motivate a developer to use more of these test patterns on their own software development projects? I know what your probably going to say, more time and more money!!! I myself have discovered a few tricks, and have changed the way I develop software so that I have enough time to do more testing and use more of the test patterns that Marc is talking about in this article. Marc has suggested a few ideas in his article that are worth considering.
 
Interested in your feedback and experiences,
 
Kent

GeneralRe: Give Me a break!, is this really practical (interested in feedback)memberKeith Farmer9 Jan '04 - 11:22 
(stream of unconsciousness warning)
 
I think it is practical, actually. As suggested in another comment, automated testing of certain types of objects (IEnumerator, not IEnumerable, etc) can be made part of the build, as it should. Also, having a catalog of testable things and the ways in which they can be tested can give good cues for the design of new things.
 
As for which are essential? That of course is up to the project. Given the nature of the work I've had to perform over the last couple years, anything involving collections is fair game, as is object persistence and application state. For me (and I imagine most), this is the typical application model and, in my experience, testing is at best hand-held and inconsistent.
 
For C# development, NUnit strikes me as a fairly good way for automated testing. It has some improvements that could be made for IDE integration, though, to make it less hands-on, and always used (at compile-time, for instance -- one less click). The idea of automatic testing of classes that conform to an interface would be a great start. I think the biggest impediment is getting people to take the time to devise these tests, and once the tests are created, getting the data to use for them.
 
.....
 
What I'd *really* like is to have pattern support in the programming language, or at least the framework. C# has delegate: Singleton would be reasonable to add, and IFactory could be added to the framework.
 
Bridges and Adapters could be cobbled together, at least as a type of object that you initialize with knowledge of the classes in question; I think they'd need language-level support to be compile-time checked. Perhaps databinding would be a good route?
QuestionWho is going to pay ?memberStuart Kinnear7 Jan '04 - 0:40 
Testing is great in theory, but it is difficult at best to get customers to pay for the initial code let alone the 40% overhead for unit tests. Unfortunately a lot of customers only look at the cosmetics and unit testing does not cover GUIs, they don't often see under the hood.
 
I found unit testing useful on critical parts of an application, but for most part a diligent step through the code and/or development of prototyped components are just as effective.
 
The patterns you have described look great on paper but as you say hide the complexity and difficulties one can have simply designing and defining test criteria especially with asynchronous processes. Due to the dynamic nature of programming, one may destroy wholesale sections of code: if an array of tests are created around that code you have the extra overhead of removing the tests or redesigning them to accommodate the new coding.
 
To sum up, the hardest part is working out that balance of what needs testing and keeping a very tidy house when developing the tests so that it is easy to manage the tests.
 
(It would also be useful if you could try to demonstrate say a small asynchronous app against the patterns you have described, and maybe a scope change effect on the tests with analysis of the change impact.)
 

Smile | :) My two bobs worth..
AnswerRe: Who is going to pay ?editorMarc Clifton7 Jan '04 - 6:04 
Stuart Kinnear wrote:
Testing is great in theory, but it is difficult at best to get customers to pay for the initial code let alone the 40% overhead for unit tests.
 
Yup. But what the customer doesn't realize is that he's paying for testing one way or the other. The question is, can unit testing effectively replace some of the QA process?
 
Stuart Kinnear wrote:
Unfortunately a lot of customers only look at the cosmetics and unit testing does not cover GUIs, they don't often see under the hood.
 
Here you hit right on the end. This is an issue that I'm trying to get my arms around, because not being able to interact at the GUI level with unit testing is a serious drawback, IMHO.
 
Stuart Kinnear wrote:
if an array of tests are created around that code you have the extra overhead of removing the tests or redesigning them to accommodate the new coding.
 
Exactly. Like documentation, unit tests become a maintenance liability. This is supposed to trade off with the time savings they provide. This is like a jellyfish-it squirms and writhes away from your grasp. It's impossible to prove one way or the other, that unit testing saves time. I think the only thing that gives some assurance of saving time is the skill of the programmer.
 
Stuart Kinnear wrote:
(It would also be useful if you could try to demonstrate say a small asynchronous app against the patterns you have described, and maybe a scope change effect on the tests with analysis of the change impact.)
 
An excellent suggestion!
 
Thanks for the feedback,
 
Marc
 

 
Latest AAL Article
My blog
Join my forum!
GeneralRe: Who is going to pay ?sussAnonymous15 Jan '04 - 16:06 
Thanks Marc, I feel that you are the only one who has replied so, who has read my comments properly.
 
I am not saying "don't do unit testing", I am not that shortsighted. In fact I wrote an article a year or two back on unit testing for Microsoft Access in Pinnacle Publishing's Smart Access magazine.
 
What I am saying however, is that we live in commercial world, therefore it is important to try and judge what impact unit testing will have in terms of time, cost and maintenance.
 
It is all well and good to set up hundreds of tests, but what of getting the project complete and on time and within budget? What is the life of the project 1 year, 2 or 20. I would say the way this industry is going 3 to 5 years is lucky.
 
In "compromise mode", I suggest:
- that all code should be written, as far as possible, to allow the hookup of an unit testing framework. This is so that tests can be applied when desired without impact to the system.
- that the critical sections of the application be identified and tests written only for them.
- that time should be spent how to properly organise tests so that they can be easily maintained.

Smile | :)
 


AnswerRe: Who is going to pay ?sussKentr7 Jan '04 - 6:56 
If the customer knew what they would save by requiring the developers to write unit tests, I think they would be willing to pay. I don't know of a customer that has enjoyed dealing with bugs and problems. I have been on some projects where the bugs were so bad that they almost cancelled the project. Unit tests are kind of like insurance. Without unit tests, I think it is a risky proposition to develop any kind of software application.
 
I have personally seen the benefits from writing good unit tests, and what is difficult to understand is that unit tests in most cases actually saved time. How does a developer test changes that are down in the core of the application? Are they really going to make sure that a single change (that may affect many parts of the app) are tested without a good unit test? We both know the answer to that question.
 
Last but not least, unit tests are no gaurantee that the software is going to work well, but it surely is better than the other alternatives we have that are not cutting it.
 
Something worth considering.
 
Kent
 

AnswerRe: Who is going to pay ?memberlemur214 Jan '04 - 2:21 
"Testing is great in theory"?
 
I'm sorry, but I think you're taking a very narrow and short-term view of software development.
 
Testing (of which unit-testing is one facet) is something that is crucial to any software project and the more complex the project, the more complex and thorough the testing needs to be. Customers *may* only look at cosmetics as you say but they'll always complain if it doesn't work because of a bug "under the hood" that wasn't picked up because of a lack of unit-testing.
 
A good testing strategy (including unit testing) is especially important if you're talking about developing software that will be maintained by many developers and released according to a quarterly release-schedule to several customers. Then testing is for YOUR benefit. Yes, stepping through code is good and should be performed by the developer *during* development, but writing a good unit test harness protects your code for the future. Repeatedly stepping through thousands of lines of code every time a module changes is far too expensive an activity.
 
Imagine what it would be like if a developer adds code to the module you wrote 9 months ago and the bug it causes in your code (because the then-correct assumptions you made aren't applicable now) isn't found until 3 months later by a customer. Still think you or someone else can find what's wrong in the 30k lines of code you wrote last year? Probably not without a lot of effort, time and expense.
 
This is when unit testing comes into its own - the developer adding the bug would have run the unit test which would have shown him or her that they've caused a regression in the module and shouldn't release the code they've just added. As someone else has pointed out, testing is an insurance policy for the longer-term.
 
As to your comment about having to maintain test harnesses as code is added and removed - yes I agree its a pain, but that's life and a price that simply has to be accepted if you want to write reliable, maintainable software that your customers are happy with and continue to be happy with. Ultimately, they're the ones who keep you in employment.
 
So in response to your question of who pays? You do. You're investing in your software's future after all. If you can get a contract that also pays for testing time, then count yourself ahead in the game.
 
Kev

GeneralThe point is...memberNorman Fung15 Jan '04 - 2:30 
I think we're missing the point here. The article isn't about why we need to conduct unit test. The article isn't about why customer should pay for unit test. The article isn't about why we should allocate adequate resource to quality assurance. These are business issues: If you plan too aggressively, the risk of overrunning the budget will, inherently, be higher. When you overrun your budget, the first place to cut-cost, naturally, is quality assurance and documentation.
 
What Marc contributed is a set of test patterns which provides us the necessary foundation/mental framework to help eliminate blind spots in executing unit test and development of test plans.

 
Norman Fung
AnswerRe: Who is going to pay ?sussAnonymous10 Feb '04 - 12:59 
The cost of testing should be in your initial estimate for the project. If the customer shows concern about the cost of testing (either money or time), you, as a developer/engineer, must show them the benefits that come from unit testing.
 
Take for instance the Pharmaceutical industry. Could you imagine what would happen if the FDA did not enforce rigorous testing on new and existing drugs? And who do you think pays for that testing?
AnswerRe: Who is going to pay ?sussAnonymous17 Oct '05 - 2:23 
I think most of the points about negatives against unit testing are made by those who have never done a project in this way.
 
Unit testing saves time, creates higher quality code and ensures that the code delivered is as close to the customers requirements as possible (not more not less). It answers the question of "are you finsished?" which is difficult without test cases and it means you can refactor/redisign/expand/fix a system so simply because you can test the behavoiur of the code.
 
As for developer productivity ask anyone who does unit testing correctly how much time they spend in the debugger - it will be close to never.
 
To the comment that unit testing requires upfront design this I believe is incorrect. Unit testing requires upfront tests - this is one of the biggest benifits of unit testing - you write code to pass tests and then you can refactor to design. You don't design code, write code to the design and then write tests to the code (which is, if one thinks about it - the completely wrong way round.)
 
For example TDD says: customer wants a search engine, they/we write up test lists and test data such as "Si" should find "Simon" and "Simone" but not "Jessica". Then the programmers write test fixtures to test against those requirements. The design is one which best meets those customer requirements.
 
Also, testing the GUI is not a massive issue. The GUI should be an extremely thin layer ontop of the code. You test the code and you've tested 99.9% of your program - the GUI is just .1%. Of course you still have to test the GUI but you aren't testing your entire application - you are mostly testing that the GUI layers calls your system correctly.
GeneralIncorrect URLsmembernetclectic5 Jan '04 - 22:13 
the urls for the 'Previous articles in the series' are incorrect, they should be .asp not .html.
 

another great article though Smile | :)
GeneralRe: Incorrect URLseditorMarc Clifton6 Jan '04 - 3:16 
netclectic wrote:
the urls for the 'Previous articles in the series' are incorrect, they should be .asp not .html.
 
D'Oh! | :doh: Fixed!
 
Thanks for pointing that out.
 
Marc
 
Latest AAL Article
My blog
Join my forum!
GeneralStill an incorrect URLmemberMikeBeard6 Jan '04 - 9:21 
Mark,
 
Great article. I always enjoy reading your articles.
 
The link at the top for "Fixture Setup/Teardown, Test Repetition, And Performance Tests" looks like it should be '...\..autp4.asp' rather than the '...\..aut4.asp' (or something similar, I am going on memory here). The link you have for it further on in the article is correct.
 
I'll reiterate the question that Nitron had: How do you find time? Smile | :) However you do it, keep up the good work!
 
Mike
GeneralInterface Test PatternmemberJonathan de Halleux5 Jan '04 - 21:54 
Nice article! I liked your introduction on NUnit testing. You really got to the point.
 
I would to propose another pattern: Interface Test Pattern which would be a "higher level" pattern (a pattern using other patterns) that could test all the classes that implement an interface.
 
What I'm thinking of is , for example, writting a test fixture for IEnumerable and then automatically test all classes implenting this interface.
 

 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test PatterneditorMarc Clifton6 Jan '04 - 3:18 
Jonathan de Halleux wrote:
I would to propose another pattern: Interface Test Pattern which would be a "higher level" pattern (a pattern using other patterns) that could test all the classes that implement an interface.
 
Excellent idea!
 
Marc
 
Latest AAL Article
My blog
Join my forum!
GeneralRe: Interface Test PatternmemberJonathan de Halleux6 Jan '04 - 3:58 
Ok, here I go with my ideas on the implementation of the InterfaceTest Pattern:
 
We will need a new TestFixture type that is intends to test interfaces implementation. Here are some important points (and new attributes):
 
- [InterfaceTestFixtureAttribute]: The objective is to design a way to create a single TextFixture for an interface and apply it to every class that implements the interface. This attribute denotes a testfixture class that tests interfaces.
 
- [InstanceProviderAttribute] The tester should be able to provide "interface instance providers" that will create new instance, manipulate it and return it to the test class. For example, if you want to test IEnumerableArrayList, you may first want to create a ArrayList, fill it with some elements and then apply the tests on the interface. Testing an empty ArrayList is pretty much useless.
 
- [InterfaceTest]: A problem with the above is that we need to use the class provided before the provider produces. A possible solution is to use a base class InterfaceTest that defines a public method Current:
 
public Object Current{get;set;}
 
This method can then be used at compile time to get a grip on the interface instance (see example below).
 
Let's see a bit of code that illustrates all that:
 

First of all, the provider class, which does not provide a particular interface, but is a provider for a class. Therefore one provider can be used to test all the interfaces that the class implements.
 
[InstanceProvider(typeof(MyClass))]
public class MyClassProvider
{
// this property is used by NUnit to get 
// an instance of MyClass
// the create instance attribute let's nunit find
// the generator property
[CreateInstance]
public MyClass Instance {get...}
}
 
Note that this provider could be reused in other
interface test if the MyClass would implement
multiple interfaces.
 
Then, the InterfaceTest base class:
 
public class InterfaceTest
{
public Object Current {get;}
}
 
Ok, now the interface test class:
 
[InterfaceTestFixture(typeof(IMyInterface))]
public MyInterfaceTest : IInterfaceTest
{
[Test]
public void Test()
{
// get an instance
IMyInterface if = (IMyInterface)Current; 
// do some tests
}
}
 
So what would NUnit do to get things working (pseudo-code)
 
providers = Create a type -> provider map;
 
foreach( interfaceTest in the test assembly)
{
foreach( class that implement the testedInterface)
{
// if no provider, go to the next class
if (!providers.Contains(class))
continue;
 
// create an instance of the tester class
interfaceTest t = new interfaceTest();
// create a new instance of the interface
t.Current = providers[class].Instance;
// do tests, with t
...
}
}
 
Comments ?
 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test PatterneditorMarc Clifton6 Jan '04 - 3:20 
It also just occurred to me that testing class and method attributes, like [Serializable], can be automated.
 
Marc
 
Latest AAL Article
My blog
Join my forum!
GeneralRe: Interface Test PatternmemberKeith Farmer6 Jan '04 - 8:55 
Nifty idea. The only limitation I see off-hand is in the case where the interface doesn't specify the form the output takes. EG: IEnumerable. It simply specifies that an Enumerator can be had -- it doesn't specify what order, etc, to expect. The compiler will ensure that IEnumerable is implemented, which I think is about as far as it could be taken.
 
It would be trivial to extend this to testing subclasses of a given base class. Same limitation regarding overridden members, but I would somewhat expect that specifications are more likely to exist for classes than interfaces.
GeneralRe: Interface Test PatternmemberJonathan de Halleux7 Jan '04 - 1:18 
Keith Farmer wrote:
Nifty idea. The only limitation I see off-hand is in the case where the interface doesn't specify the form the output takes. EG: IEnumerable. It simply specifies that an Enumerator can be had -- it doesn't specify what order, etc, to expect. The compiler will ensure that IEnumerable is implemented, which I think is about as far as it could be taken.
 
Well ensuring that GetEnumerator() actually returns a non null enumerator automatically is already a (useless) test.
 
Ok, IEnumerable is not a good example, but take IEnumerator. There is quite a number of tests that you could be automated, no matter what object type is iterated:
 
- Reset should reset the enumerator,;
- Current should fail if MoveNext was not called,
- MoveNext should fail if it is called after the last element, etc...
 
When you are implementing custom enumerator, this kind of test should be automated so you know your custom enumerator class has the expected behavior.

 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test PatternmemberKeith Farmer9 Jan '04 - 10:59 
Right.. In that instance, the behavior is part of the interface specification.
GeneralRe: Interface Test Patternmemberpiers72 Mar '04 - 1:10 
I was pondering something similar the other day. I brought up a WebControl in the VS designer and the whole think bombed out with a stack overflow exception. The source of the problem wasn't immediately obvious, and though a more through unit test would have found it the way I actually located it was to write a unit test that tested all the System.Web.UI.Controls in the assembly for basic 'control-ness' - ie that all their properties could be succesfully read straight after construction. There I found my problem (and incidentally a few others).
 
So the concept of interface testing applies to any 'interface', rather than just those with a capital I - ie any derived class always inherits some functionality from the base class that should also be 'regression' tested when the derived class is tested. This seems to suggest three things:
 
  • Unit tests need to be distributed along with any class intended for derivation (or even just any non-sealed class)
  • Unit testing frameworks need to have a mechanism for discovering unit tests that apply to base classes, and applying them to the derived class being tested
  • 'Reference' / library tests for common class types should be more widely available.
 
Do we have a generally agreed on library for .net unit tests yet?
GeneralRe: Interface Test PatternmemberJonathan de Halleux2 Mar '04 - 2:51 
piers7 wrote:
a unit test that tested all the System.Web.UI.Controls in the assembly for basic 'control-ness' - ie that all their properties could be succesfully read straight after construction.
 
Hi, I have implemented a similar concept in my Unit library (GUnit) which tests types. However, it is different from yours because it asks the user to provide "initialize" instances of the type:
 
[TypeFixture(typeof(System.Web.UI.Control))]
public class ControlTest
{
    [Provider(typeof(MyControl)]
    public MyControl ProvideMyControl()
    {
       ...
    }
 
    [Test]
    public void SomeTest(System.Web.UI.Control ctrl)
    {
        ...
    }
}
 
Of course, we could further imporve this by letting the framework load entire namespaces...
 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test Patternmemberpholser4 Mar '04 - 12:04 
piers7 wrote:
Do we have a generally agreed on library for .net unit tests yet?
 
lots of folks are using, and nearly all extensions flocking to, NUnit...works great for me....
GeneralRe: Interface Test PatterneditorMarc Clifton4 Mar '04 - 12:12 
pholser wrote:
lots of folks are using, and nearly all extensions flocking to, NUnit...works great for me....
 
hehe. Every read Jonathan Livingston Seagull? Big Grin | :-D
 
Marc
 
Microsoft MVP, Visual C#
GeneralRe: Interface Test PatternmemberJonathan de Halleux4 Mar '04 - 13:36 
Marc, this Jonathan Livingston Seagull story has a lot of "historical" conotation with me. In fact, my folks named me after this movie/book... but somehow my father swithched bird and started to call me "pelican" which later on became "peli", This is my "official" name now.
 
NUnit is in fact the dominant and most used unit test framework, (although csUnit is trying to get a grip on this too but I don't really the point, thought they do not bring anything new into the game).
 
Anyway, after sending a few message on the NUnit forums, the answers were really like: "our solution is the best, don't bother with inovative ideas". Fact is they are stuck in their minimalist design! Am-I the only one feeling Unit Testing needs "a kick in the butt". I mean, we are in the era of RAD, so logically you would hope to get tests generated automatically or do some more intelligent testing that what is proposed in NUnit.
 
NUnit has opened the eyes of many people to the power of Reflection and meta data but I'm sure there is much work to do here. For example, combining IL exploration, executaion graph, and CodeDom generation, a unit test framework should be able to generate "empty" test classes whith one method for each execution path. Therefore, the tester knows how much tests he has to write...
 

 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test PatterneditorMarc Clifton4 Mar '04 - 13:46 
Jonathan de Halleux wrote:
Am-I the only one feeling Unit Testing needs "a kick in the butt". I mean, we are in the era of RAD, so logically you would hope to get tests generated automatically or do some more intelligent testing that what is proposed in NUnit.
 
I totally agree. When I first looked at NUnit, I laughed my head off--it was like, come on, this is *all* that it does? And there's a community of people oohing and aahing over it? Unbelievable. And even worse, there was no semblence of bringing some formal engineering practices to unit testing. It reminded me of the days when us 15 year old kids would get together and yack about the latest cool technology without a clue as to what we were really talking about. But since NUnit has its roots in Java, I don't really expect much more *cough* intelligence out of the community.
 
(yes, I am biased. I'm trying not to be, but hey, if there's a platform, I'll stand on it until I'm shoved off of it!)
 
Jonathan de Halleux wrote:
NUnit has opened the eyes of many people to the power of Reflection and meta data but I'm sure there is much work to do here. For example, combining IL exploration, executaion graph, and CodeDom generation, a unit test framework should be able to generate "empty" test classes whith one method for each execution path. Therefore, the tester knows how much tests he has to write...
 
Absolutely. We're progressing in that direction with VTS. There's a few things on the todo list that are simple and are higher priority (like running unit tests automatically from the command line and unloading/reloading assemblies), but then it's on to forward engineering and things of that nature. Eduard on the AUT site has been making major contributions to VTS.
 
Unfortunately, I've been so swamped that I can't do much right now myself. Frown | :(
 
Marc
 
Microsoft MVP, Visual C#
GeneralRe: Interface Test Patternmemberpiers74 Mar '04 - 18:18 
No sorry, I meant a library for the *tests*, not the framework for running them.
 
Not (obviously) a library full of people's highly-specific unit tests, but the generic ones: reference test harnesses for classes inheriting from 'wellknown' bases like Control (Web / Windows) and Component for example.
 
(Put it this way, if you were writing a device driver, would you write your test harness from scratch, or use a standard one, and write specific tests for your specific functionality)
 
Now admittedly each test implementation has a degree of framework-specificity about it, but the underlying test code is normally fairly portable.
 
My original point was that as I started writing my generic System.Web.UI.Control test it occurred to me that a) someone must have written this before and b) if not I should probably post it somewhere
GeneralRe: Interface Test PatternmemberJonathan de Halleux4 Mar '04 - 20:58 
piers7 wrote:
My original point was that as I started writing my generic System.Web.UI.Control test it occurred to me that a) someone must have written this before and b) if not I should probably post it somewhere
 
a) I don't know any implementation.
b) GUnit (sorry about lamming with this) is built such that you can create your own fixture. Therefore, we can think about a fixture that creates a control, try to call each property and do that for all the properties. The framework can take care of separating each "property" call into 1 separate test. Is that what you are looking for ?

 
Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Interface Test Patternmemberpholser4 Mar '04 - 11:59 
http://www.placebosoft.com/abstract-test.html

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 4 Mar 2004
Article Copyright 2004 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid