The pillars of good tests in C#

Encoder Quick Response Code in C# The pillars of good tests

The pillars of good tests
QR Code Maker In Visual C#.NET
Using Barcode drawer for .NET framework Control to generate, create QR Code image in Visual Studio .NET applications.
www.OnBarcode.com
Decode QR Code JIS X 0510 In C#
Using Barcode reader for .NET Control to read, scan read, scan image in VS .NET applications.
www.OnBarcode.com
Another way to make code more maintainable is to remove duplication in tests.
Make ECC200 In Visual C#
Using Barcode drawer for .NET Control to generate, create ECC200 image in .NET applications.
www.OnBarcode.com
Matrix Printer In C#.NET
Using Barcode encoder for .NET framework Control to generate, create 2D Barcode image in Visual Studio .NET applications.
www.OnBarcode.com
7.2.2 Removing duplication
Generating UPC Code In Visual C#
Using Barcode generator for .NET framework Control to generate, create UPC-A image in .NET framework applications.
www.OnBarcode.com
Draw Code 128 Code Set B In C#
Using Barcode creation for .NET Control to generate, create Code 128 Code Set B image in VS .NET applications.
www.OnBarcode.com
Duplication in our unit tests can hurt us as developers just as much as (if not more than) duplication in production code. The don t repeat yourself (DRY) principle should be in effect in test code as in production code. Duplicated code means more code to change when one aspect we test against changes. Changing a constructor or changing the semantics of using a class can have a large effect on tests that have a lot of duplicated code. To understand why, let s begin with a simple example of a test, seen in listing 7.5.
EAN-13 Supplement 5 Printer In C#
Using Barcode maker for VS .NET Control to generate, create GS1 - 13 image in Visual Studio .NET applications.
www.OnBarcode.com
Draw USPS PLANET Barcode In C#
Using Barcode encoder for Visual Studio .NET Control to generate, create USPS PLANET Barcode image in .NET framework applications.
www.OnBarcode.com
Listing 7.5 A class under test, and a test that uses it
Draw QR-Code In .NET Framework
Using Barcode generator for ASP.NET Control to generate, create Quick Response Code image in ASP.NET applications.
www.OnBarcode.com
Decoding QR-Code In None
Using Barcode reader for Software Control to read, scan read, scan image in Software applications.
www.OnBarcode.com
public class LogAnalyzer { public bool IsValid(string fileName) { if (fileName.Length < 8) { return true; } return false; } } [TestFixture] public class LogAnalyzerTestsMaintainable { [Test] public void IsValid_LengthBiggerThan8_IsFalse() { LogAnalyzer logan = new LogAnalyzer(); bool valid = logan.IsValid("123456789"); Assert.IsFalse(valid); } }
UCC.EAN - 128 Maker In Objective-C
Using Barcode maker for iPhone Control to generate, create EAN / UCC - 13 image in iPhone applications.
www.OnBarcode.com
EAN128 Creator In Visual Basic .NET
Using Barcode creator for Visual Studio .NET Control to generate, create UCC.EAN - 128 image in .NET framework applications.
www.OnBarcode.com
Writing maintainable tests
Paint UPC-A Supplement 2 In None
Using Barcode printer for Font Control to generate, create GTIN - 12 image in Font applications.
www.OnBarcode.com
Barcode Scanner In None
Using Barcode recognizer for Software Control to read, scan read, scan image in Software applications.
www.OnBarcode.com
The test at the bottom of listing 7.5 seems reasonable, until you introduce another test for the same class and end up with two tests, as in listing 7.6.
USS-128 Creator In .NET Framework
Using Barcode maker for ASP.NET Control to generate, create EAN / UCC - 13 image in ASP.NET applications.
www.OnBarcode.com
Barcode Drawer In Visual Studio .NET
Using Barcode drawer for Reporting Service Control to generate, create Barcode image in Reporting Service applications.
www.OnBarcode.com
Listing 7.6 Two tests with duplication
Code 128 Code Set B Generation In Objective-C
Using Barcode creation for iPad Control to generate, create Code 128C image in iPad applications.
www.OnBarcode.com
Code 128A Drawer In Java
Using Barcode generator for Android Control to generate, create ANSI/AIM Code 128 image in Android applications.
www.OnBarcode.com
[Test] public void IsValid_LengthBiggerThan8_IsFalse() { LogAnalyzer logan = new LogAnalyzer(); bool valid = logan.IsValid("123456789"); Assert.IsFalse(valid); } [Test] public void IsValid_LengthSmallerThan8_IsTrue() { LogAnalyzer logan = new LogAnalyzer(); bool valid = logan.IsValid("1234567"); Assert.IsTrue(valid); }
Drawing EAN13 In Java
Using Barcode encoder for Java Control to generate, create GTIN - 13 image in Java applications.
www.OnBarcode.com
Creating USS-128 In Java
Using Barcode generator for Java Control to generate, create EAN / UCC - 14 image in Java applications.
www.OnBarcode.com
What s wrong with the tests in listing 7.6 The main problem is that, if the way you use LogAnalyzer changes (its semantics), the tests will have to be maintained independently of each other, leading to more maintenance work. Listing 7.7 shows an example of such a change.
Listing 7.7 LogAnalyzer with changed semantics that now requires initialization
public class LogAnalyzer { private bool initialized=false; public bool IsValid(string fileName) { if(!initialized) { throw new NotInitializedException( "The analyzer.Initialize() method should be" + " called before any other operation!"); }
The pillars of good tests
if (fileName.Length < 8) { return true; } return false; } public void Initialize() { //initialization logic here ... initialized=true; } }
Now, the two tests in listing 7.6 will both break because they both neglect to call Initialize() against the LogAnalyzer class. Because we have code duplication (both of the tests create the class within the test), we need to go into each one and change it to call Initialize(). We can refactor the tests to remove the duplication by creating the LogAnalyzer in a CreateDefaultAnalyzer() method that both tests can call. We could also push the creation and initialization up into a new setup method in our test class.
Removing duplication using a helper method
Listing 7.8 shows how you could refactor the tests into a more maintainable state by introducing a shared factory method that creates a default instance of LogAnalyzer. Assuming all the tests were written to use this factory method, we could then add a call to Initialize() within that factory method instead of changing all the tests to call Initialize().
Listing 7.8 Adding the Initialize() call in the factory method
[Test] public void IsValid_LengthBiggerThan8_IsFalse() { LogAnalyzer logan = GetNewAnalyzer(); bool valid = logan.IsValid("123456789"); Assert.IsFalse(valid); }
Writing maintainable tests
[Test] public void IsValid_LengthSmallerThan8_IsTrue() { LogAnalyzer logan = GetNewAnalyzer(); bool valid = logan.IsValid("1234567"); Assert.IsTrue(valid); } private LogAnalyzer GetNewAnalyzer() { LogAnalyzer analyzer = new LogAnalyzer(); analyzer.Initialize(); return analyzer; }
Factory methods aren t the only way to remove duplication in tests, as the next section shows.
Removing duplication using [SetUp]
We could also easily initialize LogAnalyzer within the Setup method, as shown in listing 7.9.
Listing 7.9 Using a setup method to remove duplication
[SetUp] public void Setup() { logan=new LogAnalyzer(); logan.Initialize(); } private LogAnalyzer logan= null; [Test] public void IsValid_LengthBiggerThan8_IsFalse() { bool valid = logan.IsValid("123456789"); Assert.IsFalse(valid); } [Test] public void IsValid_LengthSmallerThan8_IsTrue() {
The pillars of good tests
bool valid = logan.IsValid("1234567"); Assert.IsTrue(valid); }
In this case, we don t even need a line that creates the analyzer object in each test: a shared class instance is initialized before each test with a new instance of LogAnalyzer, and then Initialize() is called on that instance. But beware: using a setup method to remove duplication isn t always a good idea, as I explain in the next section.
7.2.3 Using setup methods in a maintainable manner
The Setup() method is easy to use. In fact, it s almost too easy to use enough so that developers tend to use it for things it was not meant for, and tests become less readable and maintainable. Nevertheless, setup methods have several limitations, which you can get around using simple helper methods:
Setup methods can only help when you need to initialize things. Setup methods aren t always the best candidate for duplication removal. Removing duplication isn t always about creating and initializing new instances of objects. Sometimes it s about removing duplication in assertion logic, calling out code in a specific way. Setup methods can t have parameters or return values. Setup methods can t be used as factory methods that return values. They re run before the test executes, so they must be more generic in the way they work. Tests sometimes need to request specific things or call shared code with a parameter for the specific test (for example, retrieve an object and set its property to a specific value). Setup methods should only contain code that applies to all the tests in the current test class, or the method will be harder to read and understand.
Now that we know the basic limitations of setup methods, let s see how developers try to get around them in their quest to use setup methods no matter what, instead of using helper methods. Developers abuse setup methods in several ways:
Copyright © OnBarcode.com . All rights reserved.