c# itextsharp pdfreader not opened with owner password : Cut pages out of pdf online software SDK dll windows winforms wpf web forms The%20Art%20of%20Unit%20Testing%20with%20Examples%20in%20.NET%20(Manning%202009)21-part1053

Writing maintainable tests
185
The test at the bottom of listing 7.5 seems reasonable, until you intro-
duce another test for the same class and end up with two tests, as in 
listing 7.6.
Listing 7.6  Two tests with duplication
[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);
}
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 mainte-
nance 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!");
}
Cut pages out of pdf online - remove PDF pages in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Provides Users with Mature Document Manipulating Function for Deleting PDF Pages
delete pages from a pdf reader; delete pages in pdf
Cut pages out of pdf online - VB.NET PDF Page Delete Library: remove PDF pages in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Visual Basic Sample Codes to Delete PDF Document Page in .NET
delete a page from a pdf in preview; delete page from pdf file
186
CHAPTER 7    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 main-
tainable  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 
Ini-
tialize()
.
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);
}
C# HTML5 PDF Viewer SDK to view PDF document online in C#.NET
Image: Copy, Paste, Cut Image in Page. Link: Edit URL. Bookmark can view PDF document in single page or continue pages. Support to zoom in and zoom out PDF page.
delete pages pdf file; delete pages from pdf in reader
VB.NET PDF- View PDF Online with VB.NET HTML5 PDF Viewer
Remove Image from PDF Page. Image: Copy, Paste, Cut Image in can view PDF document in single page or continue pages. Support to zoom in and zoom out PDF page.
delete pages from a pdf; delete pages in pdf reader
Writing maintainable tests
187
[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()
{
VB.NET Image: Image Cropping SDK to Cut Out Image, Picture and
and easy to use .NET solution for developers to crop / cut out image file This online tutorial page will illustrate the image cropping function from following
delete pdf pages ipad; add and delete pages in pdf online
VB.NET PDF Text Extract Library: extract text content from PDF
Extract highlighted text out of PDF document. Best VB.NET PDF text extraction SDK library and component for Online Visual Basic .NET class source code for quick
reader extract pages from pdf; delete a page from a pdf online
188
CHAPTER 7    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 ini-
tializing  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 exam-
ple, 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:
C# PDF Text Extract Library: extract text content from PDF file in
Free online source code for extracting text from adobe Ability to extract highlighted text out of PDF C# example code for text extraction from all PDF pages.
delete pdf pages acrobat; delete page in pdf document
VB.NET PDF - View PDF with WPF PDF Viewer for VB.NET
Image from PDF Page. Image: Copy, Paste, Cut Image in PDF pages extract, copy, paste, C#.NET rotate PDF pages, C#.NET Abilities to zoom in and zoom out PDF page.
cut pages from pdf online; delete pages of pdf
Writing maintainable tests
189
Initializing objects in the setup method that are only used in some of 
the tests in the class
Having setup code that’s long and hard to understand
Setting up mocks and fake objects within the setup method
Let’s take a closer look at these.
Initializing objects that are only used by some of the tests
This sin is a deadly one. Once you commit it, it becomes difficult to 
maintain the tests or even read them, because the setup method quickly 
becomes loaded with objects that are specific only to some of the tests. 
Listing 7.10 shows what our test class would look like if we initialized a 
FileInfo
object setup method but only used it in one test ?.
Listing 7.10  A poorly implemented Setup() method
[SetUp]
public void Setup()
{
logan=new LogAnalyzer();
logan.Initialize();
fileInfo=new FileInfo("c:\\someFile.txt"); 
}
private FileInfo fileInfo = null;
private LogAnalyzer logan= null;
[Test]
public void IsValid_LengthBiggerThan8_IsFalse()
{
bool valid = logan.IsValid("123456789");
Assert.IsFalse(valid);
}
[Test]
public void IsValid_BadFileInfoInput_returnsFalse()
{
bool valid = logan.IsValid(fileInfo);
Assert.IsFalse(valid);
}
Used only  
in one test
?
C# WPF PDF Viewer SDK to view PDF document in C#.NET
Image from PDF Page. Image: Copy, Paste, Cut Image in PDF pages extract, copy, paste, C#.NET rotate PDF pages, C#.NET Abilities to zoom in and zoom out PDF page.
copy pages from pdf to new pdf; delete page numbers in pdf
C# PDF Form Data fill-in Library: auto fill-in PDF form data in C#
Free online C# sample code can help users to fill in fill in form field in specified position of adobe PDF file. Able to fill out all PDF form field in C#.NET.
delete page pdf file reader; delete pdf page acrobat
190
CHAPTER 7    The pillars of good tests
[Test]
public void IsValid_LengthSmallerThan8_IsTrue()
{
bool valid = logan.IsValid("1234567");
Assert.IsTrue(valid);
}
private LogAnalyzer GetNewAnalyzer()
{
...
}
Why is the setup method in listing 7.10 less maintainable? Because, to 
read the tests for the first time and understand why they break, you 
need to do the following:
1
Go through the setup method to understand what is being initialized.
2
Assume that objects in the setup method are used in all tests.
3
Find out later you were wrong, and read the tests again more care-
fully to see which test uses the objects that may be causing the prob-
lems.
4
Dive deeper into the test code for no good reason, taking more time 
and effort to understand what the code does.
Always consider the readers of your tests when writing the tests. Imag-
ine this is the first time they read them. Make sure they don’t get angry.
Having setup code that’s long and hard to understand
Because the setup method provides only one place in the test to initial-
ize things, developers tend to initialize many things, which inevitably is 
cumbersome to read and understand. One solution is to refactor the 
calls to initialize specific things into helper methods that are called from 
the setup method. This means that refactoring the setup method is usu-
ally a good idea; the more readable it is, the more readable your test 
class will be.
But there’s a fine line between over-refactoring and readability. Over-
refactoring can lead to less readable code. This is a matter of personal 
preference. You need to watch for when your code is becoming less 
readable.  I  recommend  getting  feedback  from  a  partner  during  the 
VB.NET PDF- HTML5 PDF Viewer for VB.NET Project
Remove Image from PDF Page. Image: Copy, Paste, Cut Image in NET comment annotate PDF, VB.NET delete PDF pages, VB.NET PDF page and zoom in or zoom out PDF page
delete page from pdf document; delete page on pdf reader
VB.NET PDF - WPF PDF Viewer for VB.NET Program
Image from PDF Page. Image: Copy, Paste, Cut Image in Online Guide for Using RasterEdge WPF PDF Viewer to View PDF pages, zoom in or zoom out PDF pages and go to
cut pages from pdf preview; copy pages from pdf into new pdf
Writing maintainable tests
191
refactoring. We all can become too enamored with code we’ve written, 
and having a second pair of eyes involved in refactoring can lead to good 
and objective results. Having a peer do a code review (a test review) 
after the fact is also good, but not as productive as doing it as it happens.
Setting up mocks and fakes in the setup method
It’s not always a bad idea to use the setup method to create mocks and 
fake objects, but it’s important that only those mocks and fakes that are 
used in 
all the tests
in the class are initialized in the setup method, or it 
will become hard to read and maintain.
My preference is to have each test create its own mocks and stubs by 
calling helper methods within  the  test, so that the reader of  the  test 
knows exactly what is going on, without needing to jump from test to 
setup to understand the full picture.
7.2.4 Enforcing test isolation
The lack of test isolation is the biggest single cause of test blockage I’ve 
seen while consulting and working on unit tests. The basic concept is 
that a test should always run in its own little world, isolated from even 
the 
knowledge
that other tests out there may do similar or different things.
The test that cried “fail”
One project I was 
involved 
in had uni
t tests behaving strangely,
 and they 
got even stranger as t
ime went on.
A
 test would fail
 and then suddenly 
pass for a couple of days straight
.
A
 day 
later,
i
t would fail,
 seemingly 
randomly,
 and other t
imes 
i
t would pass even 
if code was changed to 
remove or change 
i
ts behavior.
 It got to the point where developers 
would tell
 each other,
 “Ah,
i
t’s OK.
 If 
i
t somet
imes passes,
 that means 
i
passes.
It turned out that the test was calling out a different test as part of 
i
ts 
code,
 and when the other test failed,
i
t would break the first test
.
It only took us three days to figure this out
,
 after spending a month 
liv-
ing w
i
th the si
tuat
ion.
 When we finally had the test working correct
ly,
 we 
discovered that we had a bunch of 
real
 bugs 
in our code that we were 
ignoring because we were gett
ing what we thought were false posi
t
ives 
from the failing test
.
The story of the boy who cried “wolf” holds true 
even 
in development
.
192
CHAPTER 7    The pillars of good tests
When  tests  aren’t  isolated  well,  they  can  step  on  each  other’s  toes 
enough to make you miserable, making you regret deciding to try unit 
testing on the project, and promising  yourself never again. I’ve seen 
this happen. We don’t bother looking for problems in the tests, so when 
there’s a problem with the tests, it can take a lot of time to find it.
There are several test “smells” that can hint at broken test isolation:
Constrained test order
—Tests expecting to be run in a specific order or 
expecting information from other test results
Hidden test call
—Tests calling other tests
Shared-state corruption
—Tests sharing in-memory state without rolling 
back
External-shared-state corruption
—Integration tests with shared resources 
and no rollback
Let’s look at these simple 
anti-patterns
.
Anti-pattern: constrained test order
This problem arises when tests are coded to expect a specific state in 
memory, in an external resource, or in the current test class—a state 
that was created by running other tests in the  same class before the 
current test. The problem is that most test platforms (including NUnit, 
JUnit, and MbUnit) don’t guarantee that tests will run in a specific 
order, so what passes today may fail tomorrow.
For example, listing 7.11 shows a test against 
LogAnalyzer
that expects 
that an earlier test had already called 
Initialize()
.
Listing 7.11  Constrained test order: the second test will fail if it runs first
[TestFixture]
public class IsolationsAntiPatterns
{
private LogAnalyzer logan;
[Test]
public void CreateAnalyzer_BadFileName_ReturnsFalse()
{
logan = new LogAnalyzer();
logan.Initialize();
Writing maintainable tests
193
bool valid = logan.IsValid("abc");
Assert.That(valid, Is.False);
}
[Test]
public void CreateAnalyzer_GoodFileName_ReturnsTrue()
{
bool valid = logan.IsValid("abcdefg");
Assert.That(valid, Is.True);
}
}
A  myriad of problems can  occur  when  tests  don’t enforce isolation. 
Here’s a short list:
A test may suddenly start breaking when a new version of the test 
framework is introduced that runs the tests in a different order.
Running a subset of the tests may produce different results than run-
ning all the tests or a different subset of the tests.
Maintaining  the  tests  is  more  cumbersome,  because  you  need  to 
worry about how other tests relate to particular tests and how each 
one affects state.
Your tests may fail or pass for the wrong reasons; for example, a dif-
ferent test may have failed or passed before it, leaving the resources 
in an unknown state.
Removing or changing some tests may affect the outcomes of other 
tests.
It’s difficult to name your tests appropriately because they test more 
than a single thing.
There are a couple of common patterns that lead to poor test isolation:
Flow testing
—A developer writes tests that must run in a specific order 
so  that  they  can  test  flow  execution,  a  big  use  case  composed  of 
many actions, or a full integration test where each test is one step in 
that full test.
Laziness in cleanup
—A developer is lazy and doesn’t return any state 
her test may have changed back to its original form, and other devel-
194
CHAPTER 7    The pillars of good tests
opers  write  tests  that  depend  on  this  symptom,  knowingly  or 
unknowingly.
These problems can be solved in various manners:
Flow testing
—Instead of writing flow-related tests in unit tests (long-
running use cases, for example), consider using some sort of integra-
tion testing framework like FIT or FitNesse, or QA-related products 
such as AutomatedQA, WinRunner, and the like.
Laziness in cleanup—
If you’re too lazy to clean up your database after 
testing, your filesystem after testing, or your memory-based objects, 
consider moving to a different profession. This isn’t a job for you.
Anti-pattern: hidden test call
In this anti-pattern, tests contain one or more direct calls to other tests 
in the same class or other test classes, which causes tests to depend on 
one another. For example, listing 7.12 shows the
CreateAnalyzer_Good 
NameAndBadNameUsage
test calling a different test at the end, creating a 
dependency between the tests and breaking both of them as isolated 
units.
Listing 7.12  One test calling another breaks isolation and introduces a dependency
[TestFixture]
public class HiddenTestCall
{
private LogAnalyzer logan;
[Test]
public void CreateAnalyzer_GoodNameAndBadNameUsage()
{
logan = new LogAnalyzer();
logan.Initialize();
bool valid = logan.IsValid("abc");
Assert.That(valid, Is.False);
CreateAnalyzer_GoodFileName_ReturnsTrue();
}
[Test]
public void CreateAnalyzer_GoodFileName_ReturnsTrue()
{
Documents you may be interested
Documents you may be interested