c# itextsharp pdfreader not opened with owner password : Delete pages pdf online software control project winforms web page windows UWP The%20Art%20of%20Unit%20Testing%20with%20Examples%20in%20.NET%20(Manning%202009)22-part1054

Writing maintainable tests
195
bool valid = logan.IsValid("abcdefg");
Assert.That(valid, Is.True);
}
}
This type of dependency can cause several problems:
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 and 
when they call each other.
Tests may fail or pass for the wrong reasons. For example, a differ-
ent test may have failed, thus failing your test or not calling it at all. 
Or  a  different  test  may  have  left  some  shared  variables  in  an 
unknown state.
Changing some tests may affect the outcome of other tests.
It’s difficult to clearly name tests that call other tests.
Here are a few causes for this problem:
Flow testing
—A developer writes tests that need to 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.
Trying to remove duplication
—A developer tries to remove duplication in 
the tests by calling other tests (which have code they don’t want the 
current test to repeat).
Laziness in separating the tests
—A developer is lazy and doesn’t take the 
time to create  a  separate test  and  refactor the code appropriately, 
instead taking a shortcut and calling a different test.
Here are some solutions for those problems:
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.
Delete pages 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 page pdf; delete pages on pdf file
Delete pages 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 pages from a pdf in preview; add or remove pages from pdf
196
CHAPTER 7    The pillars of good tests
Trying to remove duplication
—Don’t ever remove duplication by calling 
another test from a test. You’re preventing that test from relying on 
the setup and teardown methods in the class and are essentially run-
ning  two  tests  in  one (because the calling test has an assertion as 
well as the test being called). Instead, refactor the code you  don’t 
want to write twice into a third method that both your test and the 
other test call.
Laziness in separating the tests
—If you’re too lazy to separate your tests, 
think of all the extra work you’ll have to do if  you don’t separate 
them. Try to imagine a world where the current test you’re writing is 
the only test in the system, so it can’t rely on any other test.
Anti-pattern: shared-state corruption
This  anti-pattern  manifests  in two  major ways,  independent of  each 
other:
Tests  touch  shared  resources  (either  in  memory  or  in  external 
resources, such as databases, filesystems, and so on) without clean-
ing up or rolling back any changes they make to those resources.
Tests don’t set up the initial state they need before they start run-
ning, relying on the state to be there.
Either of these situations will cause the symptoms we’ll look at shortly.
The problem is that tests rely on specific state to have consistent pass/
fail behavior. If a test doesn’t control the state it expects, or other tests 
corrupt that state for whatever reason, the test can’t run properly or 
report the correct result consistently.
For example, assume we have a 
Person
class with simple features: it has 
a list of phone numbers and the ability to search for a number by spec-
ifying the beginning of the number. Listing 7.13 shows a couple of tests 
that don’t clean up or set up a 
Person
object instance correctly.
Listing 7.13  Shared-state corruption by a test
[TestFixture]
public class SharedStateCorruption
{
Person person = new Person();  
Defines shared  
Person state
C# PDF File & Page Process Library SDK for C#.net, ASP.NET, MVC
C# view PDF online, C# convert PDF to tiff, C# read PDF, C# convert PDF to text, C# extract PDF pages, C# comment annotate PDF, C# delete PDF pages, C# convert
delete page in pdf file; delete blank pages in pdf files
C# PDF Page Insert Library: insert pages into PDF file in C#.net
document files by C# code, how to rotate PDF document page, how to delete PDF page using C# .NET, how to reorganize PDF document pages and how
add and delete pages from pdf; delete pdf pages reader
Writing maintainable tests
197
[Test]
public void CreateAnalyzer_GoodFileName_ReturnsTrue()
{
person.AddNumber("055-4556684(34)");
string found = 
person.FindPhoneStartingWith("055");
Assert.AreEqual("055-4556684(34)", found);
}
[Test]
public void FindPhoneStartingWith_NoNumbers_ReturnsNull()
{
string found = 
person.FindPhoneStartingWith("0");
Assert.IsNull(found);
}
}
In this example, the second test (expecting a 
null
return value) will fail 
because the previous test has already added a number ? to the 
Person
instance.
This type of problem causes a number of symptoms:
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 test is more cumbersome, because you may break 
the state for other tests, breaking those tests without realizing it.
Your test may fail or pass for the wrong reason; for example, a differ-
ent test may have failed or passed before it, leaving the shared state 
in a problematic condition, or it may not have cleaned up after it ran.
Changing some tests may affect the outcomes of other tests, seem-
ingly randomly. 
Here are a few causes of this problem:
Not setting up state before each test
—A developer doesn’t set up the state 
required for the test, or assumes the state was already correct.
Using  shared  state
—A  developer  uses  shared  memory  or  external 
resources for more than one test without taking precautions.
Changes  
shared state
?
Reads  
shared state
C# HTML5 PDF Viewer SDK to view PDF document online in C#.NET
C# view PDF online, C# convert PDF to tiff, C# read PDF, C# convert PDF to text, C# extract PDF pages, C# comment annotate PDF, C# delete PDF pages, C# convert
delete page in pdf preview; delete pages from a pdf file
VB.NET PDF Page Insert Library: insert pages into PDF file in vb.
add and insert one or multiple pages to existing adobe PDF document in VB.NET. Ability to create a blank PDF page with related by using following online VB.NET
delete page from pdf reader; delete pdf pages in reader
198
CHAPTER 7    The pillars of good tests
Using static instances in tests
—A developer sets static state that’s used in 
other tests.
Here are some solutions:
Not setting up state before each test
—This is a mandatory practice when 
writing unit tests. Use either a setup method or call specific helper 
methods at the beginning of the test to ensure the state is what you 
expect it to be.
Using shared state
—In many cases, you don’t need to share state at all. 
Having separate instances of an object for each test is the safest way 
to go.
Using  static  instances  in  tests—
You  need  to  be  careful  how  your  tests 
manage static state. Be sure to clean up the static state using setup or 
teardown  methods.  Sometimes  it’s  effective  to  use  direct  helper 
method calls to clearly reset the static state from within the test. If 
you’re testing singletons, it’s worth adding public or internal setters 
so your tests can reset them to a clean object instance.
Anti-pattern: external-shared-state corruption
This anti-pattern is similar to the in-memory state corruption pattern, 
but it happens in integration-style testing:
Tests  touch  shared  resources  (either  in  memory  or  in  external 
resources, such as databases, filesystems, and so on) without clean-
ing up or rolling back any changes they make to those resources.
Tests don’t set up the initial state they need before they start run-
ning, relying on the state to be there.
Now  that we’ve  looked  at  isolating  tests,  let’s  manage  our 
assert
s  to 
make sure we get the full story when a test fails.
7.2.5 Avoiding multiple asserts
To understand the problem of multiple asserts, let’s take a look at the 
example in listing 7.14.
Listing 7.14  A test that contains multiple asserts
[Test]
public void CheckVariousSumResults()
{
VB.NET PDF- View PDF Online with VB.NET HTML5 PDF Viewer
RasterEdge. PRODUCTS: ONLINE DEMOS: Online HTML5 Document Viewer; Online XDoc.PDF C# File: Split PDF; C# Page: Insert PDF pages; C# Page: Delete PDF pages;
delete pages pdf; cut pages out of pdf
VB.NET PDF - Convert PDF Online with VB.NET HTML5 PDF Viewer
C# view PDF online, C# convert PDF to tiff, C# read PDF, C# convert PDF to text, C# extract PDF pages, C# comment annotate PDF, C# delete PDF pages, C# convert
delete pages in pdf online; cut pages out of pdf online
Writing maintainable tests
199
Assert.AreEqual(3, Sum(1001, 1, 2));
Assert.AreEqual(3, Sum(1, 1001, 2));
Assert.AreEqual(3, Sum(1, 2, 1001));
}
There’s more than one test in this test method. The author of the test 
method tried to save some time by including three tests as three simple 
asserts. What’s the problem here? When asserts fail, they throw excep-
tions.  (In  NUnit’s  case,  they  throw  a  special 
AssertException
that’s 
caught by the NUnit test runner, which understands this exception as 
a signal that the current test method has failed.) Once an assert clause 
throws an exception, no other line executes in the test method. That 
means that, if the first assert in listing 7.14 failed, the other two assert 
clauses would never execute.
There are several ways to achieve the same goal:
Create a separate test for each assert.
Use parameterized tests.
Wrap the assert call with 
try
-
catch.
Why does it matter if some asserts aren’t executed?
If only one assert fails,
 you never know 
if the other asserts 
in that same 
test method would have failed or not
.
 You may 
think
 you know
,
 but 
i
t’s 
an assumpt
ion unt
il
 you can prove 
i
t w
i
th a failing or passing assert
.
When people see only part of the picture,
 they tend to make a 
judgment 
call
 about the state of the system,
 which can turn out wrong.
The more 
informat
ion you have about all
 the asserts that have failed or passed,
the better equipped you are to understand where 
in the system a bug 
may 
lie,
 and where 
i
t doesn’t
.
I’ve gone on w
ild goose chases hunt
ing for bugs that weren’t there be-
cause only one assert out of several
 failed.
 Had I bothered to check 
whether the other asserts failed or passed,
 I might have realized that the 
bug was 
in a different 
locat
ion.
Somet
imes people go and find bugs that they think are real,
 but when 
they “fix” them,
 the assert that previously failed passes  and  the  
other 
asserts 
in that test fail
 (or cont
inue to fail
)
.
 Somet
imes you can’t see the
C# HTML5 PDF Viewer SDK to convert and export PDF document to
C# view PDF online, C# convert PDF to tiff, C# read PDF, C# convert PDF to text, C# extract PDF pages, C# comment annotate PDF, C# delete PDF pages, C# convert
delete pages of pdf reader; delete blank page in pdf online
VB.NET PDF - Annotate PDF Online with VB.NET HTML5 PDF Viewer
VB.NET PDF - Annotate PDF Online with VB.NET HTML5 PDF Viewer. Explanation about transparency. VB.NET HTML5 PDF Viewer: Annotate PDF Online. This
delete page from pdf preview; delete page from pdf online
200
CHAPTER 7    The pillars of good tests
Refactoring into multiple tests
Multiple asserts are really multiple tests without the benefit of test iso-
lation;  a  failing  test  causes  the  other  asserts  (tests)  to  not  execute. 
Instead, we can create separate test methods with meaningful names 
that represent each test case. Listing 7.15 shows an example of refac-
toring from the code from listing 7.14.
Listing 7.15  A refactored test class with three different tests
[Test]
public void Sum_1001AsFirstParam_Returns3()
{
Assert.AreEqual(3, Sum(1001, 1, 2));
}
[Test]
public void Sum_1001AsMiddleParam_Returns3()
{
Assert.AreEqual(3, Sum(1, 1001, 2));
}
[Test]
public void Sum_1001AsThirdParam_Returns3()
{
Assert.AreEqual(3, Sum(1, 2, 1001));
}
As you can see, the refactoring in listing 7.15 gives us three separate 
tests, each with a slightly different name indicating how we’re testing 
the unit. The benefit is that, if one of those tests fails, the others will 
still run. Unfortunately, this is too verbose, and most developers would 
feel this refactoring is overkill for the benefit. Although I disagree that 
full
 problem,
 so fixing part of 
i
t can 
introduce new bugs 
into the system,
which w
ill
 only be discovered after you’ve uncovered each assert’s re-
sul
t
.
That’s why 
i
t’s 
important that all
 the asserts have a chance to run,
 even 
if other asserts have failed before.
 In most cases,
 that means putt
ing 
single asserts 
in tests.
Writing maintainable tests
201
it’s overkill (it took about 20  seconds of  work to  get the benefit),  I 
agree that the verbosity is  an issue. It’s  an issue  because developers 
won’t do it, and we end up with our original problem.
That’s  why  many  unit-testing  frameworks,  including  MbUnit  and 
NUnit, have a custom attribute you can use that achieves the same goal 
with much more concise syntax.
Using parameterized tests
Both MbUnit  and  NUnit support  the  notion  of  parameterized tests 
using a special attribute called 
[RowTest]
. Listing 7.16 shows how you 
can  use  the 
[RowTest]
and 
[Row]
attributes  (found  in  NUnit.Exten-
sions.dll under the NUnit bin directory) to run the same test with dif-
ferent parameters in a single test method. Notice that, when you use 
the 
[RowTest]
attribute, it replaces the 
[Test]
attribute in NUnit.
Listing 7.16  A refactored test class using parameterized tests
[RowTest]
[Row(1001,1,2,3)]
[Row(1,1001,2,3)]
[Row(1,2,1001,3)]
public void SumTests(int x,int y, int z,int expected)
{
Assert.AreEqual(expected, Sum(x, y, z));
}
NOTE
To  use 
[RowTest]
in  NUnit,  you’ll  need  to  add  a  reference  to 
NUnit.Extensions.dll, which is found in the bin directory of NUnit’s 
installation folder. 
Parameterized test methods in NUnit and MbUnit are different from 
regular tests in that they can take parameters. They also expect at least 
one 
[RowTest]
attribute  to  be  placed  on  top  of  the  current  method 
instead of a regular 
[Test]
attribute. The attribute takes any number of 
parameters, which are then mapped at runtime to the parameters that 
the test method expects in its signature. 
The example in listing 7.16 expects four arguments. We call an assert 
method  with  the first  three  parameters,  and  use  the  last one  as  the 
202
CHAPTER 7    The pillars of good tests
expected value. This gives us a declarative way of creating a single test 
with different inputs.
The best thing about this is that, if one of the 
[RowTest]
attributes fails, 
the other attributes are still executed by the test runner, so we see the 
full picture of pass/fail states in all tests.
Wrapping with try-catch
Some people think it’s a good idea to use a 
try
-
catch
block for each 
assert to catch and write its exception to the console, and then continue 
to the next statement, bypassing the problematic nature of exceptions 
in tests. I think using parameterized tests is a far better way of achiev-
ing  the  same  thing.  Use  parameterized  tests  instead  of 
try
-
catch
around multiple asserts.
Now that we  know how  to avoid multiple  asserts acting as multiple 
tests, let’s look at multiple asserts being used to test multiple aspects of 
a single object.
7.2.6 Avoiding testing multiple aspects of the same object
Let’s look at another example of a test with multiple asserts, but this 
time it’s not trying to act as multiple tests in one test, it’s trying to check 
multiple aspects of the same state. If even one aspect fails, we need to 
know about it. Listing 7.17 shows such a test.
Listing 7.17  Testing multiple aspects of the same object in one test
[Test]
public void   
Analyze_SimpleStringLine_UsesDefaulTabDelimiterToParseFields()
{
LogAnalyzer log = new LogAnalyzer();
AnalyzedOutput output =
log.Analyze("10:05\tOpen\tRoy");
Assert.AreEqual(1,output.LineCount);
Assert.AreEqual("10:05",output.GetLine(1)[0]);
Assert.AreEqual("Open",output.GetLine(1)[1]);
Assert.AreEqual("Roy",output.GetLine(1)[2]);
}
Writing maintainable tests
203
This  example  is  testing  that  the  parse  output  from  the 
LogAnalyzer
worked  by  testing  each  field  in  the  result  object  separately.  They 
should all work, or the test should fail.
Making tests more maintainable
Listing 7.18 shows a way to refactor the test from listing 7.17 so that 
it’s easier to read and maintain.
Listing 7.18  Comparing objects instead of using multiple asserts
[Test]
public void 
Analyze_SimpleStringLine_UsesDefaulTabDelimiterToParseFields2()
{
LogAnalyzer log = new LogAnalyzer();
AnalyzedOutput expected = new AnalyzedOutput(); 
expected.AddLine("10:05", "Open", "Roy");
AnalyzedOutput output =
log.Analyze("10:05\tOpen\tRoy");
Assert.AreEqual(expected,output);     
}
Instead of adding multiple asserts, we can create a full object to com-
pare against, set all the properties that should be on that object, and 
compare the result and the expected object in one assert. The advan-
tage of this approach is that it’s much easier to understand what we’re 
testing and to recognize  that this is one logical block that should be 
passing, not many separate tests.
Note that, for this  kind of testing,  the  objects being compared  must 
override the 
Equals()
method, or the comparison between the objects 
won’t work. Some people find this an unacceptable compromise. I use 
it from time to time, but am happy to go either way. Use your own dis-
cretion.
Overriding ToString()
Another approach you might try is to override the 
ToString()
method 
of  compared objects so  that, if  tests fail, you’ll get  more  meaningful 
Sets up  
an expected  
object
Compares  
expected and  
actual objects
204
CHAPTER 7    The pillars of good tests
error messages. For example, here’s the output of the test in listing 7.18 
when it fails. 
TestCase 'AOUT.CH7.LogAn.Tests.MultipleAsserts
.Analyze_SimpleStringLine_UsesDefaulTabDelimiterToParseFields2'
failed:
Expected: <AOUT.CH789.LogAn.AnalyzedOutput>
But was:  <AOUT.CH789.LogAn.AnalyzedOutput>
C:\GlobalShare\InSync\Book\Code\ARtOfUniTesting
\LogAn.Tests\MultipleAsserts.cs(41,0): 
at AOUT.CH7.LogAn.Tests.MultipleAsserts
.Analyze_SimpleStringLine_UsesDefaulTabDelimiterToParseFields2()
Not very helpful, is it?
By implementing 
ToString()
in both the 
AnalyzedOutput
class and the 
LineInfo
class (which are part of the object model being compared), we 
can get more readable output from the tests. Listing 7.19 shows the two 
implementations of the 
ToString()
methods in the classes under test, 
followed by the resulting test output.
Listing 7.19  Implementing ToString() in compared classes for cleaner output
///Overriding ToString inside The AnalyzedOutput Object//////////////
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (LineInfo line in lines)
{
sb.Append(line.ToString());
}
return sb.ToString();
}
///Overriding ToString inside each LineInfo Object//////////////
public override string ToString()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.fields.Length; i++)
{
sb.Append(this[i]);
sb.Append(",");
}
Documents you may be interested
Documents you may be interested