c# itextsharp pdfreader not opened with owner password : Delete blank page from pdf Library application class asp.net html wpf ajax The%20Art%20of%20Unit%20Testing%20with%20Examples%20in%20.NET%20(Manning%202009)20-part1052

Writing trustworthy tests
175
Consider the simple test in listing 7.1.
Listing 7.1  A simple test against the LogAnalyzer class
[Test]
public void SemanticsChange()
{
LogAnalyzer logan = new LogAnalyzer();
Assert.IsFalse(logan.IsValid("abc"));  
}
Let’s say that a semantics change has  been made to the 
LogAnalyzer
class, in the form of an 
Initialize
method. You now have to call 
Ini-
tialize
on the 
LogAnalyzer
class before calling any of the other meth-
ods on it.
If you introduce this change in the production code, the assert line 
?
of 
the test in listing 7.1 will throw an exception because 
Initialize
was 
not called. The test will be broken, but it’s still a valid test. The func-
tionality it tests still works, but the semantics of using the object under 
test has changed.
In this case, we need to change the test to match the new semantics, as 
shown in listing 7.2.
Listing 7.2  The changed test using the new semantics of LogAnalyzer
[Test]
public void SemanticsChange()
{
LogAnalyzer logan = new LogAnalyzer();
logan.Initialize();
Assert.IsFalse(logan.IsValid("abc"));
}
Changing semantics accounts for most of the bad experiences develop-
ers have with writing and maintaining unit tests, because the burden of 
changing  tests  while  the  API of the  code under test keeps  changing 
gets bigger and bigger. Listing 7.3 shows a more maintainable version 
of the test in listing 7.2.
?
Delete blank page from pdf - 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 file; delete page from pdf online
Delete blank page from pdf - 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 pdf online; delete page from pdf
176
CHAPTER 7    The pillars of good tests
Listing 7.3  A refactored test using a factory method 
[Test]
public void SemanticsChange()
{
LogAnalyzer logan = MakeDefaultAnalyzer();
Assert.IsFalse(logan.IsValid("abc"));
}
public static LogAnalyzer MakeDefaultAnalyzer()
{
LogAnalyzer analyzer = new LogAnalyzer(); 
analyzer.Initialize();
return analyzer;
}
In this case, the refactored test uses a utility factory method ?. We can 
do the same for other tests and have them use the same utility method. 
Then,  if  the  semantics  of  creating  and  initializing  the  object  should 
change  again,  we  don’t  need to  change  all the  tests that  create  this 
object; we just need to change one little utility method. We’ll see other 
maintainability techniques later in this chapter.
Conflicting or invalid tests
A conflict problem arises when the production code introduces a new 
feature that’s in direct conflict with a test. This means that, instead of 
the test discovering a bug, it discovers conflicting requirements.
Let’s look at a short example. Suppose the customer requests 
LogAna-
lyzer
to not allow filenames shorter than  three letters. The analyzer 
should throw an exception in that case. The feature is implemented and 
tests are written.
Much later on, the customer realizes that three-letter filenames do have 
a use and requests that they be handled in a special way. The feature is 
added and the production code changed. Then we write new tests so 
that the production code no longer throws an exception. Suddenly, an 
old test (the one with a three-letter filename) breaks because it expects 
an exception. Fixing the production code to make that test pass would 
break the new test that expects three-letter filenames to be handled in a 
special way.
Uses  
factory  
method
?
VB.NET PDF Page Insert Library: insert pages into PDF file in vb.
Easy to Use VB.NET APIs to Add a New Blank Page to PDF Document in VB.NET Program. doc2.Save(outPutFilePath). Add and Insert Blank Page to PDF File Using VB.
delete pages pdf preview; delete pdf pages acrobat
C# PDF Page Insert Library: insert pages into PDF file in C#.net
as how to merge PDF document files by C# code, how to rotate PDF document page, how to delete PDF page using C# .NET Add and Insert Blank Page to PDF File in
acrobat export pages from pdf; delete page on pdf
Writing trustworthy tests
177
This either-or scenario, where only one of two tests can pass, serves as 
a  warning that these may be conflicting  tests.  In  this case, you first 
need to make sure that the tests are in conflict. Once that’s confirmed, 
you  need  to  decide  which  requirement  to  keep.  You  should  then 
remove (not comment out) the invalid requirement and its tests.
Conflicting  tests  can  sometimes  point  out  problems  in  customer 
requirements, and the customer may need to decide on the validity of 
each requirement.
Renaming or refactoring tests
An unreadable test is more of a problem than a solution. It can hinder 
your code’s readability and your understanding of any problems it finds.
If you encounter a test that has a bad name or that can be made more 
maintainable, change the test code (but don’t change the basic func-
tionality of the test). Listing 7.3 showed one such example of refactor-
ing a test for maintainability, which also makes it a lot more readable.
Eliminating duplicate tests
When dealing with a team of developers, it’s common to come across 
multiple tests written by different developers for the same functionality. 
I’m not crazy about removing duplicate tests for a couple of reasons:
The more (good) tests you have, the more certain you are to catch bugs.
You can read the tests and see different ways or semantics of testing 
the same thing.
Here are some of the cons of having duplicate tests:
It may be harder to maintain several different tests that provide the 
same functionality.
Some  tests  may  be  higher  quality  than  others,  and  you  need  to 
review them all for correctness.
Multiple tests may break  when a  single thing  doesn’t  work. (This 
may not really be a con.)
Similar tests must be named differently, or the tests can be spread 
across different classes.
Multiple tests may create more maintainability issues.
C# Create PDF Library SDK to convert PDF from other file formats
Create and save editable PDF with a blank page, bookmarks, links, signatures, etc. Create a new PDF Document with one Blank Page in C# Project.
delete a page from a pdf without acrobat; delete page in pdf
C# PDF Page Replace Library: replace PDF pages in C#.net, ASP.NET
pageIdx, The page index of the deleted blank page. 0
delete pages from a pdf reader; delete pages from pdf
178
CHAPTER 7    The pillars of good tests
Here are some pros:
Tests may have little differences, and so can be thought of as testing 
the same things slightly differently. They may make for a larger and 
better picture of the object being tested.
Some tests may be more expressive than others, so more tests may 
improve the chances of test readability.
Although, as I said, I am not crazy about removing duplicate tests, I 
usually do so; the cons usually outweigh the pros.
7.1.2 Avoiding logic in tests
The chances of having bugs in your tests increase almost exponentially 
as you include more and more logic in them. I’ve seen plenty of tests 
that should have been simple turned into dynamically changing logic, 
random-number generating, thread-creating, file-writing monsters that 
are  little  test  engines  in  their  own right.  Sadly,  because  they  had  a 
[Test]
attribute on them, the writer didn’t consider  that  they  might 
have bugs or didn’t write them in a maintainable manner. Those test 
monsters take more time to debug and verify than they save. 
But all monsters start out small. Often, a guru in the company will look 
at a test and start thinking, “What if we made the method loop and cre-
ate random numbers as input? We’d surely find lots more  bugs that 
way!” And you will, especially in your tests. Test bugs are one of the 
most  annoying  things  for  developers,  because  you’ll  almost  never 
search for the cause of a failing test in the test itself. 
If you have any of the following inside a test method, your test contains 
logic that should not be there:
❂ switch
if
, or 
else
statements
foreach
for
, or 
while
loops
A test that contains logic is usually testing more than one thing at a 
time, which isn’t recommended, because the test is less readable and 
more fragile. But test logic  also  adds complexity that may contain  a 
hidden bug.
Tests should, as a general rule, be a series of method calls with no con-
trol  flows,  not  even 
try
-
catch
, and with assert calls.  Anything more 
complex causes the following problems:
C# Word - Insert Blank Word Page in C#.NET
such as how to merge Word document files by C# code, how to rotate Word document page, how to delete Word page Add and Insert a blank Page to Word File in C#.
add or remove pages from pdf; delete blank pages in pdf files
C# PowerPoint - Insert Blank PowerPoint Page in C#.NET
document files by C# code, how to rotate PowerPoint document page, how to delete PowerPoint page using C# Add and Insert a blank Page to PowerPoint File in C#.
acrobat remove pages from pdf; delete blank pages in pdf
Writing trustworthy tests
179
The test is harder to read and understand.
The test is hard to re-create. (Imagine a multithreaded test, or a test 
with random numbers that suddenly fail.)
The test is more likely to have a bug or to test the wrong thing.
Naming the test may be harder because it does multiple things.
Generally, monster tests replace original simpler tests, and that makes 
it harder to find bugs in the production code. If you must create a mon-
ster test, it should be 
added to
and not 
replace
existing tests.
7.1.3 Testing only one thing
If your test contains more than a single assert, it may be testing more 
than one thing. That doesn’t sound so bad until you go to name your 
test or consider what happens if the first assert fails.
Naming a test may seem like a simple task, but if you’re testing more 
than one thing, giving the test a good name that indicates what is being 
tested becomes almost impossible. When you test just one thing, nam-
ing the test is easy.
A  failed  assert  message
in  most  test  frameworks  (NUnit  included) 
throws a special type of exception that’s caught by the test framework 
runner. When the test framework catches that exception, it means the 
test has failed. Unfortunately, exceptions, by design, don’t let the code 
continue. The method exits on the same line the exception is thrown. 
Listing 7.4 shows an example. If the first assert (
IsFalse()
) fails, it will 
throw an exception, which means the second assert will never run.
Listing 7.4  A test with multiple asserts
[Test]
public void TestWithMultipleAsserts()
{
LogAnalyzer logan = MakeDefaultAnalyzer();
Assert.IsFalse(logan.IsValid("abc"));
Assert.IsTrue(logan.IsValid("abcde.txt"));
}
VB.NET PDF: Get Started with PDF Library
Field Data. Data: Auto Fill-in Field Data. Field: Insert, Delete, Update Field. of .NET PDF SDK with Simple Sample Code for Creating Blank Page to PDF in VB
delete pages from pdf without acrobat; acrobat remove pages from pdf
VB.NET Create PDF Library SDK to convert PDF from other file
Create and save editable PDF with a blank page, bookmarks, links, signatures, etc. VB.NET: Create a New PDF Document with One Blank Page.
delete pages out of a pdf; delete pages from pdf online
180
CHAPTER 7    The pillars of good tests
Consider assert failures as symptoms of a disease. The more symptoms 
you can find, the easier the disease will be to diagnose. After a failure, 
subsequent asserts aren’t executed, and you miss seeing other possible 
symptoms  that  could  provide  valuable  data  (symptoms)  that  would 
help you narrow your focus and discover the underlying problem. 
Running  multiple  asserts  in  a single  test  adds  complexity  with little 
value.  You  should  run  additional  asserts  in  separate,  self-contained 
unit tests so that you can see what really fails.
7.1.4 Making tests easy to run
In chapter 6, I discussed the safe green zone for tests. If developers 
don’t trust your tests to run out of the box easily and consistently, they 
won’t run them. Refactoring your tests so they’re easy to run and pro-
vide consistent results will make them feel more trustworthy. Having a 
safe green zone in your tests can lead to more confidence in your tests.
7.1.5 Assuring code coverage
To ensure good coverage for your new code, use one of the automated 
tools (for example, NCover or Visual Studio Team System Test Edi-
tion). Find a good tool and stick with it, making sure you never have 
low  coverage;  less  than  20  percent  means  you’re  missing  a  whole 
bunch of tests. You never know if the next developer will try to play 
with  your  code.  He  may  try  to  optimize  it  or  wrongly  delete  some 
essential line,  and  if you don’t have a  test  that will  fail, the mistake 
may go unnoticed.
When doing code and test reviews, you can also do a manual check, 
which is great for ad hoc testing of a test: try 
commenting out 
a line or a 
constraint check. If all tests still pass, you might be missing some tests, 
or the current tests may not be testing the right thing.
When  you  add  a  new  test  that  was  missing,  check  whether  you’ve 
added the correct test with these steps:
1
Comment out the production code you think isn’t being covered.
2
Run all the tests.
C# PDF: PDF Document Viewer & Reader SDK for Windows Forms
page. AddPage: Prior to the currently displayed PDF page to add a blank page. DeletePage: Delete the currently displayed PDF page.
delete a page from a pdf reader; delete pdf pages in preview
Writing maintainable tests
181
3
If all the tests pass, you’re missing a test or are testing the wrong 
thing. Otherwise there would have been a test somewhere that was 
expecting that line to be called, or some resulting consequence of 
that line of code to be true, and that missing test would now fail.
4
Once you’ve found a missing test, you’ll need to add it. Keep the 
code commented out and write a new test that fails, proving that the 
code you’ve commented is missing.
5
Uncomment the code you commented before.
6
The test you wrote should now pass. You’ve detected and added a 
missing test!
7
If the test still fails, it means the test may have a bug or is testing the 
wrong thing. Modify the test until it passes. Now you’ll want to see 
that the test is OK, making sure it fails when it should, and doesn’t 
just pass when it should. To make sure the test fails when it should, 
reintroduce the bug into your code (commenting out the line of pro-
duction code) and see if the test indeed fails.
As an added confidence booster, you might also try replacing various 
parameters or internal variables in your method under test with con-
stants (making a 
bool
always 
true
to see what happens, for example).
The trick to all this testing is making sure it doesn’t take up too much 
time to make it worth your while. That’s what the next section is about: 
maintainability.
Maintainability  is  one  of the  core  issues  most  developers  face  when 
writing  unit  tests.  Eventually  the  tests  seem  to  become  harder  and 
harder to maintain and understand, and every little change to the sys-
tem seems to break one test or another, even if bugs don’t exist. With 
all pieces of code, time adds a layer of “indirection” between what you 
think the code does and what it really does.
This  chapter  will  cover  some  techniques  I’ve learned  the hard  way, 
writing unit tests in various teams. They include testing only against 
7.2 Writing maintainable tests
182
CHAPTER 7    The pillars of good tests
public contracts, removing duplication in tests, and enforcing test isola-
tion, among others.
7.2.1 Testing private or protected methods
Private or protected methods are usually private for a good reason in 
the developer’s mind. Sometimes it’s to hide implementation details, so 
that the implementation can change later without the end functionality
changing.  It  could also  be for security-related or IP-related  reasons 
(obfuscation, for example).
When you test a private method, you’re testing against a contract inter-
nal  to  the  system,  which  may  well  change.  Internal  contracts  are 
dynamic, and they can change when  you refactor  the  system. When 
they change, your test could fail because some internal work is being 
done  differently, even though the overall functionality  of the system 
remains the same.
For testing purposes, the public contract (the overall functionality) is 
all that you  need  to  care  about. Testing  the  functionality  of private 
methods may lead to breaking tests, even though the overall functional-
ity is correct. 
If a method is worth testing, it might be worth making it public, static, 
or at least internal, and defining a public contract against any user of it. 
In some cases, the design may be cleaner if you put the method in a dif-
ferent class altogether. We’ll look at these approaches in a moment.
Does this mean there should eventually be no private methods in the 
code base? No. With test-driven development, we usually write tests 
against methods  that  are  public,  and  those public methods  are  later 
refactored into calling smaller, private methods. All the while, the tests 
against the public methods continue to pass.
Making methods public
Making a method public isn’t necessarily a bad thing. It may seem to 
go against the object-oriented principles you were raised on, but want-
ing to test a method means that the method has a known 
behavior
or 
con-
tract
against the calling code. By making it public, you’re making this 
Writing maintainable tests
183
official. By keeping the method private, you tell all the developers who 
come after you that they can change the implementation of the method 
without  worrying  about  unknown code  that  uses  it, because it  only 
serves as part of a larger group of things that together make up a con-
tract to the calling code.
Extracting methods to new classes
If your method contains a lot of logic that can stand on its own, or it 
uses state in the class that’s only relevant to the method in question, it 
may be a good idea to extract the method into a new class, with a spe-
cific role in the system. You can then test that class separately. Michael 
Feathers’ book, 
Working Effectively with Legacy Code
, has some good exam-
ples of this technique.
Making methods static
If your method doesn’t use any of its class’s variables, you might want 
to refactor the method by making it static. That makes it much more 
testable, but also states that this method is a sort of utility method that 
has a known public contract specified by its name.
Making methods internal
When all else fails, and you can’t afford to expose the method in an 
“official”  way, you might want to make it  internal, and then use the 
[InternalsVisibleTo("TestAssembly")]
attribute  on  the  production 
code assembly so that tests can still call that method. This is my least 
favorite approach, but sometimes there’s no choice (perhaps because of 
security reasons, lack of control over the code’s design, and so on). 
Making the method internal isn’t a great way to make sure your tests 
are  more  maintainable,  because  a  coder  can  still  feel  it’s  easier  to 
change the method. But by exposing  a method  as  an explicit  public 
contract, the coder who may change it knows that the method has a 
real usage contract he can’t break. 
Removing the method isn’t a good option because the production code 
uses the method too. Otherwise, there would be no reason to write the 
tests in the first place. 
184
CHAPTER 7    The pillars of good tests
Another way to make code more maintainable is to remove duplication
in tests.
7.2.2 Removing duplication
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 produc-
tion  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.
Listing 7.5  A class under test, and a test that uses it
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);
}
}
Documents you may be interested
Documents you may be interested