DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Unit Testing 101: Creating Flexible Test Code

Unit Testing 101: Creating Flexible Test Code

Luis Aguilar user avatar by
Luis Aguilar
·
Feb. 14, 14 · Interview
Like (0)
Save
Tweet
Share
10.92K Views

Join the DZone community and get the full member experience.

Join For Free

introduction

when going for test-driven development , we all know that the unit test code becomes critical part of the code base. additional to this, it even ends up representing a bigger percentage of the overall code base than the actual business code. is because of this that it is really important to have a solid unit test source code structure; flexible, intuitive and maintainable enough so that when the amount of unit tests grow, it does not become an uncontrollable mess.

always remember: unit testing is not done because is a nice to have or because test-driven development is trendy and cool; it is done because is needed and is critical in order to ease the development cycle and ensure product quality.

academic v.s. real life

most articles we follow on the internet on how to build unit tests often use small or reduced scopes in order to keep the concepts easy to digest and understand. for example, they demostrate how to create one or two unit tests to test a simple application feature, like a calculator capability to add two numbers. the problem raises when we get the next day in our computers at work and try to apply our newly acquired knowledge to a more realistic scope: we realize that, in real life, we would have thousands of units tests for a thousand features and not one or two like in the articles we learned from.

so, the question is: what do we do when we go beyond examples and get into testing a real-life application?

the scenario

before we can continue, lets use the scenario we mentioned previously. lets assume we are working in an online shopping application. we are about to create a rest service that allows web clients to handle orders from customers. that service will eventually feature several methods to place new orders, cancel orders, track orders, etc. we'll need to create a bunch of unit tests for that service and all of its methods.

a flexible structure

now, we have a scenario. assuming the orders service eventually will feature a bunch of methods, unit tests must cover all of these methods and all of its possible success and failure scenarios. this could result in a couple dozen test methods in no time. what do we do? do we go down the usual path and put all of these test methods in a single test class since it is testing a single component?

short answer: no. you don't do that.

we are starting to see that grouping tests per-component is not enough in order to keep test classes small, so we need to break down grouping one more level. in the case of the orders service, our next grouping level would be per-component feature . we have now two levels of unit test grouping:

  • component tests: top-level group of unit test suites that target a single component. in this case, the orders service.
  • component feature tests: sub-level that group the test suites that target a single component feature. in this case, the orders service method for placing orders.

now, how does this look in code?

the unit test code

in c#, we can create a single class composed of multiple source files. this is done by using partial classes. so, we will start by defining a new partial class that will represent a part of the component test suite class.

[testfixture]
partial class onordersservice 
{
    // more code here on a second...
}

the component test suite class uses the following naming convention:

public [partial] class on[componentname] { }

so, when reading the name we have a clear idea of what's the target component to be tested by the suite. right after the feature test suite class declaration, we start defining the component feature test suite class. this will be a class nested inside the feature test suite class.

[testfixture]
partial class onordersservice
{
    [testfixture]
    public class whenplacingorders
    {
        // component feature test methods to be added here soon...
    }
}

the component feature test suite class uses the following naming convention:

public class when[actionperformed][featurename] {}

of course, the next thing to do is add some test methods. lets expand our example:

[testfixture]
partial class onordersservice
{
    [testfixture]
    public class whenplacingorders
    {
        [test]
        public void shouldreturnorderidonvalidorderplaced()
        {
            // test code for a success scenario...
        }
        
        [test]
        public void throwerroroninvalidorderplaced()
        {
            // test code for a failure scenario...
        }
    }
}

the success scenario test methods use the following convention:

public void should[expectedoutcome]on[scenariocondition]();

.. and failure scenario use:

public void should[expectedfailure]on[failureconditions]();

before you stop reading and yell in anger on those funky class names, lets try to read textually down our hierarchy:

on orders service... when placing orders... should return order id on valid order placed.

so, by now you should be getting a clearer picture on what we are trying to achieve here. by manipulating class structures (partial and nested classes) we can organize our tests by component and then by component feature while keeping an intuitive and readable structure. this will allow us to keep test classes small and easy maintainable. if you don't trust me with the previous example, this is how the visual studio test runner looks when using our handy class structure.

now, lets say that we would like to add tests to cover the service method that cancels orders. in this case we would create a new partial class using the same onordersservice class name. we then create a new nested class called whencancellingorders .

now we have a component test suite class split in two files. each file will contain a single component feature test suite.

i think is time we discuss what naming convention these files should follow. our test runner looks pretty now, but our file structure, which has nothing to do with the runner; has to look pretty as well. we will use the following convention:

on[componentname]when[actionperformed][featurename].cs

for example:

onordersservicewhenplacingorders.cs
onordersservicewhencancellingorders.cs

there you go. now it looks good enough. we can go further and play a little with the namespaces, but that is out of the scope of this article.

conclusion

that would be it. we now have a consistent test code structure that can grow gradually as requirements and features are added. in future articles we will go through unit test method structuring and test contexts in order to delegate test contest setup code like mocking objects and such.

unit test Test suite

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Hackerman [Comic]
  • The Real Democratization of AI, and Why It Has to Be Closely Monitored
  • A Simple Union Between .NET Core and Python
  • Implementing Infinite Scroll in jOOQ

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: