By Developers, For Developers

Historical errata for Pragmatic Unit Testing in C# with NUnit

PDF PgPaper PgTypeDescriptionFixed onComments
5743TYPO

In your explanation of TestDB.cs you describe the method names PerTestSetup() and PerTestTearDown() rather than the names in the code - MySetup() and MyTearDown(). I think the PerTest… reference might be a carry over/copy/paste error from the initial code sample at the beginning of the “Per-Method Setup and Teardown” sub section, starting on print page 42.

2007-05-09
13TYPO

“if you recongize any of the warning signs below.”

should be

“if you recognize any of the warning signs below.”

2007-05-09
34SUGGEST

In the description of Assert.Less and Assert.Greater consider reordering the expalainations to match the order of the examples in the text. It currently reads as follows:
Less / Greater
Assert.Less(x, y)
Assert.Greater(x,y)
Asserts that x > y (or x < y) for numeric types, or any type
that is IComparable.

For less chance of confusion I think it should be:
Less / Greater
Assert.Less(x, y)
Assert.Greater(x,y)
Asserts that x < y (or x > y) for numeric types, or any type
that is IComparable.

2007-05-09
165TYPO

mid-way down the page the word amout is duplicated
Rewind by some allowed amount amount (not

2007-05-09
54ERROR

The “expected” integer variable needs to be a private variable of the TestLargestDataFile class, rather than local to the readTestData method, if it’s to be accessible from the TestFromFile method.

2007-05-09
7TYPO

Pretty minor: the title “Does it Document my Intent” seems to be capitalized inconsitently with the other titles. Others have “it” capitalized and it appears as if “my” should be capitalized as well.

2007-05-09
87ERROR

The URL http://www.mockobjects.org/ does not appear to be valid anymore.

There is a site on mock objects at http://www.mockobjects.com/ but the two .NET mock object implementations listed are NMock and RhinoMock.

However, the sourceforge.net URL for DotNetMock is valid.

2007-05-09
99ERROR

Text reads: “We then pass this mock-customer into the calculator and test some age calculations”. However, there is no calculator nor are there any age calculations.

Text should probably read: “We then pass this mock customer into the mailer and test the long and short greetings.”

2007-05-09
99ERROR

Confused naming convention for TestFixture class (TestCalculator) and Test method (AgeCalculation). Example illustrates a mailing application where the tests are checking the long and short greetings for a customer, not age calculations.

2007-05-09
118SUGGEST

Text reads: “In fact you can make this class private to the test code …”. The code as shown would give a compile error if the PoolForTesting class was made declared as “private” rather than the correct “internal”. Perhaps the sentence can be altered to avoid any confusion?

2007-05-09
29ERROR

“. . . what we really wanted was MinValue, so as to be less than all negative numbers as well: . . .”

Int32.MinValue is less than or equal to all negative Int32 values, but it isn’t strictly less than all of them.

2007-05-09
17ERROR

In the method \t\t
public static int Largest(int[] list)
these two lines of code:

int index, max=Int32.MaxValue;
for (index = 0; index < list.Length-1; index)

should be:

int index, max=Int32.MinValue;
for (index = 0; index <= list.Length-1; index)

2007-05-09
63TYPO

The paragraph just before 5.1 reads: There

2007-05-09
73SUGGEST

I had to read the bottom few paragraphs a few times to be sure that it was saying that the unit tests should be reading MaxEntries instead of using a hard coded value. Perhaps this could be explained a little more clearly?

2007-05-09
138ERROR

Very minor issue. Line numbers in the bottom paragraph seem to be out by 1. They should be 12 and 22.

2007-05-09
102TYPO

I just thought that I would pass along a typo that I noticed on page 102 - the first sentence in the second paragraph reads “…your first though..”. I’m sure you meant this to read “…your first thought…”.

2007-05-09
157SUGGEST

Minor thing.
Nunit-Addin hasn’t been called that for a while and though at the moment the mutantdesign url will re-route it might be best for the long term to change the name of the product to TestDriven.Net 2.0 and tghe url to http://www.testdriven.net

2007-05-09
13TYPO

There is a typo in the last sentence of “Yeah, we unit test already” paragraph:
See if you recoNGize…

2007-05-09
28TYPO

Hey, it worked! You

2007-05-09
37TYPO

Next, we have the class definition itself on line 3: each class that contains tests must be annotated with a [TestFixture] attributedeclared public (so that the test runners can find it; by default, classes are private), and it must have a public, no-parameter, constructor (the default constructor is fine).

“attribute” and “declared” should be split into separate words.

2007-05-09
37ERROR

Re: Footnote 2:

"Method names that start with the word

2007-05-09
46TYPO

AreEqual(FileInfo expected, FileInfo actual)

should be prefixed by:

FileAssert

so it reads:

FileAssert.AreEqual(FileInfo expected, FileInfo actual)

2007-05-09
47TYPO

CountDeMonet()

should probably read:

CountDeMoney()

instead.

2007-05-09
58TYPO

You might check that some data was successfully inserted
into a database and then searching for it and delete it.

“searching” should be replaced with “search.”

2007-05-09
64TYPO

"such as e-mail addresses, phone numbers, account numbers,
or file names is usually straightforward, but be aware of internationalization
issues: not only could there be issues with
the format (many countries don

2007-05-09
161TYPO

Now do the same test again, but this time add multiple items to the stack. Make sure you get the rights ones back, in the right order (the most recent item added should be the one returned).

“rights” should read “right”

2007-05-09
165ERROR

Re: “Rewind by some allowed amount amount (not past beginning of tape), then fast forward by same amount. Should be at initial location.”

Should we really be at the initial lolcation? The initial location is BOT. If we follow the second bullet and fast forward by some amount and the rewind by the same amount, we should be at the initial location (BOT). But then when we rewind by some allowed amount, we are already at the BOT so rewinding has the effect of keeping us at BOT. When we fast forward by the same amount, however, it should have the effect of moving us beyond BOT (towards EOT), as long as the amount is greater than 0. So we shouldn’t be at the initial location at this point but rather should be somewhere past the initial location, assuming that the amount is a non-zero positive value.

2007-05-09
86TYPO

Here

2007-05-09
86TYPO

"It took some time for the senior engineer
recover from a bad case of

2007-05-09
88TYPO

Each AccessController
object is responsible to controlling access to a particular
resource

2007-05-09
110SUGGEST

You mention the “DRY principle.” Never heard of it. Sorry!

2007-05-09
83TYPO

The section title, ‘Mocking sleep()’, doesn’t really seem to make sense with respect to the example code, as there’s no ‘sleep()’ operation taking place. Perhaps a more general section title, such as ‘Mock Implementations with Interfaces’ would be appropriate?

2007-05-09
87SUGGEST

I’ll add to Phil’s report by mentioning that .NET MockObjects is built on .NET 1.1 at present and while there’s an announcement from 7 (!!!) months ago about the next version being on .NET 2.0, there doesn’t seem to be much activity.

2007-05-09
72SUGGEST

Make sure your method can stand up to nothing.

This would probably read better as “… stand up to being passed nothing” or “… stand up to any input”.

2007-05-09
114SUGGEST

But there

2007-05-09
23SUGGEST

Topic: NUnit Command Line

Update the PATH variable to point to NUnit 2.4. Currently it shows 2.2.

2007-05-09
87SUGGEST

Would like to see examples using a more up-to-date mocking framework like RhinoMock (ayende.com/projects/rhino-mocks.aspx) - mockobjects seems to be abandonware.

2007-05-09
32SUGGEST

Would like to see a section - with examples - on NUnit 2.4 Constraint-Based Assert Model (nunit.org/index.php?p=constraintModel&r=2.4)

2007-05-09
40TYPO

Missing word “in” (inserted in brackets below):

"In the GUI, you select which categories of tests to include and which to exclude on the tab as shown in Figure 3.2 on this page. Just select each category you

2007-05-09
32TYPO

Last paragraph, 2nd sentence: duplicated word "For for the rest of this book we

2007-05-09
97TYPO

Section head “Faking collaberators” misspells “collaborators.”

In the first paragraph of that section, “collaberating” should be spelled as “collaborating.”

2007-10-25
38TYPO

The bottom of the Joe asks box is cut off. The last visible text is:
“That leaves the text formatting when an assertion fails,
which falls to the TextMessageWriter object that
NUnit uses internally.”

This is with Acrobat Reader 7.0.8 on debian etch i386.

2007-10-25
9TYPO

In the “About the Starter Kit” Section of Version: 2007-5-9 of the Beta:

“But the very books we published are still some of the most important ones.”

I believe the word “first” was intended?: “the very FIRST books we published”

2007-10-25
73TYPO

First paragraph:

“…even in the prescense of tests ignored…”

should be:

“…even in the presence of tests ignored…”

2007-10-25
100TYPO

End of second paragraph:

"(see the section in on page 187 for an interesting

2007-10-25
113TYPO

Second paragraph:

"… by faking the collaberator

2007-10-25
119TYPO

Last paragraph:

“This code is equivelant to the code…”

should be:

“This code is equivalent to the code…”

2007-10-25
121SUGGEST

Last paragraph:

"…you

2007-10-25
136TYPO

Second paragraph:

"…and you

2007-10-25
135TYPO

Last paragraph:

"Either way, it will be safer to do: you

2007-10-25
169ERROR

Continued from PDF page 168:

“use a finally clause to ensure that the file gets deleted, even if one of our assertions fails.”

The code actually uses the TearDown() NUnit framework method which will be called even if one of the test assertions fails.

2007-10-25
198TYPO

Section B.3 “Works On My Machine”, first paragraph:

“Another pathologic problem that turns up…”

should be:

“Another pathological problem that turns up…”

2007-10-25
200TYPO

Section “B.6 Tests Keep Breaking”, third paragraph:

“…for information on refactoring and design smells,…”

I do not think the word “smells” is correct, but I cannot deduce the proper word.

2007-10-25
201TYPO

Section “B.8 Tests Pass In One Test Runner, Not the Other”, third paragraph:

“…which may expose hidden dependancies.”

should be:

“…which may expose hidden dependencies.”

2007-10-25
202TYPO

Section “B.9 Thread state issues ”, first paragraph:

“…when it should be single-threaded and nice versa.”

should be:

“…when it should be single-threaded and vice versa.”

2007-10-25
202TYPO

Section “B.9 Thread state issues”, first paragraph:

“…but there are a couple of NUnit commandline options to try:”

should be:

“…but there are a couple of NUnit command line options to try:”

2007-10-25
205TYPO

SharpDevelop summary has a rogue letter i at the end of the summary, after the period.

2007-10-25
204SUGGEST

NAnt is mentioned a few times in the book as well as multiple times in the Resources section, perhaps an entry into the Resources section with a URL and summary would be appropriate.

2007-10-25
113ERROR

Code snippet:

“public FakeParser : Parsable”

should be:

“public class FakeParser : Parsable”

2007-10-25
119ERROR

NMock2 example code:

“parser = mocks.NewMock();”

should be:

“parser = mockery.NewMock();”

2007-10-25
200SUGGEST

Okay, the word smells is correct in that context, however, the reader(such as myself when I read this) may not know what it means. I suggest putting the word in quotes.

2007-10-25
132ERROR

I believe the text indicates that the production code class Pool will have a protected method called LastCleaned, and that to access that protected method from our tests, we will extend Pool into PoolForTesting, making the LastCleaned method public, and use PoolForTesting in our unit tests rather than Pool.
However, this will give a compile error: cannot change access modifiers when overriding ‘protected’ inherited member.
To expose the protected method LastCleaned, the user will need to use a different public method in the inherited class (like CallLastCleaned), and have it call into the protected method LastCleaned.

2007-10-25
7SUGGEST

I’ve heard “$500 million dollars” is redundant… “500 million dollars” or “$500 million” aren’t, though.

2007-10-25
20TYPO

Missing open paren in the paragraph beginning “Next, you need to compile the code”

2007-10-25
136TYPO

Correction to the correction:

“…and you’ll end up spending a lot a quality time…”

should be:

"…and you

2007-10-25
154ERROR

In the paragraph -
“Finally, at line 26 we play the part of a good neighbor and
delete the temporary file we used for the test. Note that we use a finally clause to ensure that the file gets deleted, even if one of our assertions fails.”
you reference a finally clause that is not present in the code listing RecipeTest.cs

2007-10-25
192TYPO

Jeffrey Richter. CLR via C. Microsoft Press,Redmond,WA,second edition,2006.

“CLR via C.” should be “CLR via C#.”

2007-10-25
43TYPO

Top of the page, in “Joe Asks … What is a fixture?”, Second sentence reads:

“Once the circuit board or component is mounted in the text fixture,…”

It should be “is mounted in the test fixture”

NOTE: as of time this was submitted, it soes say “test fixture” on the wiki page.

2007-10-25
96ERROR

there is an error at the code :
parser = new Parser(stream);

this should be :
parser = new DumpFileParser(stream);

(this line is taken from this code sample : )

[TestFixture]
public class DumpFileParserTest
{
private StreamWriter writer;
private DumpFileParser parser;
private MemoryStream stream;
[SetUp]
public void SetUp()
{
stream = new MemoryStream();
writer = new StreamWriter(stream);
}
[Test]
public void EmptyLine()
{
writer.WriteLine(string.Empty);
parser = new Parser(stream);
Assert.That(xxxx, xxxx);
}
}

2007-10-25
4TYPO

Footnote 3:

“It could also make you wildest dreams come true…”
Should probably be “It could also make your wildest dreams come true…”

2007-10-25
161OK

The TDD section says: “Test-driven development is a valuable technique where you
always write the tests themselves before writing the methods
that they test [wCA04]. As a nice side benefit of this style of
working, you can enjoy “test-driven design” and significantly
improve the design of your inter faces."

I find this misleading and plain wrong. Shaping up the API and the design is most definitely NOT a side-benefit. It is the primary benefit of Test-Driven Development. I would use TDD and write unit tests even if I knew that all my tests would be wiped away(by imaginary evil troll) after I am done designing the code and that would mean I have to write unit tests again.

[That’s a bit of tongue-cheek humor; sorry you found it misleading]

2007-09-27
51DEFER

This is regarding the paragraph that begins with “In this example, the method PerFixtureTest will be called …..”. I believe that the contention of the authors that TestFixtureSetup and TestFixtureTeardown being called after each test is wrong. These two methods are called only once per [TestFixture], and not once per [Test] attribute.. Hence the sequence of events, relating to the example on pages 50-51 should be:
[TestFixtureSetup]
[Setup] —-> AccountAcce()
[Teardown]
[Setup] —-> EmployeeAccess()
[Teardown]
[TestFixtureTeardown]
Thank you.

10TYPO

First line of the page marked on the page as page 10 says:

“… until then it will definitely longer …”

and should probably say:

“… until then it will definitely take longer …”

2009-12-09
138OK

On p. 138 of your book, you mention the issue of accessing internal members when test code is in a separate assembly. There is another option: use the InternalsVisibleTo attribute to make the unit test assembly a friend assembly.

2009-12-09
201DEFER

The NullableInt example won’t compile due to unassigned variables. In any case the advice is incorrect - Nullable types with null values do equate to null (Equals is overloaded).

151DEFER

The line
DatabaseConnection dbc = new DatabaseConnection();
should be above the try block.

179DEFER

The line
new RecipieForm(recipe as Recipe);
does not look right.
recipe is type FakeRecipeFile, which is a RecipeFile (and would not need an as cast), which does not seem to be a Recipe.

180TYPO

For the line
ExpectModal(PASSWORD_FAILURE, “PasswordFailureOkHandler”);
shouldn’t that be
ExpectModal(PASSWORD_FAILURE, “MessageBoxOkHandler”);
?

2009-12-09
105TYPO

“Sometimes the controller is told directly and in NUnit’s mocks” - “and” should be “as”. (1st paragraph)

2009-12-09
164OK

In the SaveAndRestore test, it might be a better example if it were refactored so that the tests did not use file I/O.

2009-12-09
164OK

In the SaveAndRestore test, it might be a better example if it were refactored so that the tests did not use file I/O.

2009-12-09
39TYPO

The line “Is.AtMost() is just an alias for Is.LessThenOrEqualTo(),” should be “Is.AtMost() is just an alias for Is.LessThanOrEqualTo(),”

2009-12-09
124TYPO

“Code analysis tools and mutation testers can help close this gap, which we’ll discuss in Chapter 7.”

is written within chapter 7 itself. Nester isn’t mentioned until chapter 8.6.

2009-12-09
53OK

First line on page 53:
Assert.That(actualCollection, List.Contains(expectedValue)

Suggestion: use Has.Member in NUnit 2.4.2 instead of the above syntax:
Assert.That(actualCollection, Has.Member(expectedValue) );

2009-12-09
167DEFER

Summary:
The code for the method createRecipe is flawed, and will not record information past the INGREDIENTS_TOKEN line of the lines ICollection into the new Recipe object.

Detail:
When I got the RecipeForm.cs file working, I found a bug in the CreateRecipe method in the RecipeFile class. Without the change, the code will never load the file properly. In the switch (tokens[0]) statement, the original code used a for loop to read the string collection lines after the INGREDIENTS_TOKEN token. This for statement doesn’t work, because there is nothing advancing the line variable to the next string in the lines ICollection.

I changed the code to use the default: case to read in the ingredients from the file. This is by no means a bullet proof solution (what if there are no ingredients to read?). I’m sure the best solution is to advance the line variable within the for loop, but I couldn’t discover how to do that.

I encountered this using Visual Studio 2005.

Original code:
foreach (string line in lines) {
string[] tokens = line.Split(delim, 2);
switch (tokens[0]) {
case NAME_TOKEN: {
recipe.Name = tokens[1];
break;
}
case INGREDIENTS_TOKEN: {
try {
int count = Int32.Parse(tokens[1]);

for (int i = 0; i < count; i) {
recipe.AddIngredient(line);
}
} catch (IOException error) {
throw new RecipeFormatException(
“Bad ingredient count: ” + error.Message);
}
break;
}
}

My change:
foreach (string line in lines) {
string[] tokens = line.Split(delim, 2);
switch (tokens[0]) {
case NAME_TOKEN: {
recipe.Name = tokens[1];
break;
}
case INGREDIENTS_TOKEN: {
try {
int count = Int32.Parse(tokens[1]);
//for (int i = 0; i < count; i) {
// recipe.AddIngredient(line);
//}
} catch (IOException error) {
throw new RecipeFormatException(
“Bad ingredient count: ” + error.Message);
}
break;
}
default: {
recipe.AddIngredient(line);
break;
}
}

Another option is to put this in another loop structure.

77TYPO

Shouldn’t anOther be another, rather than two camel-cased words?

2009-12-09
201DEFER

I have found an error in the book and I want to report it. The error is slight but I consider it worth mentioning.

On page 201, Appendix A, A.10 - C# 2.0-Specific issues there is this C# code :

[Test]
public void NullableInt() {
int? first;
Nullable second;
Assert.IsNull(first);
Assert.IsNull(second);
}

This code will not work (not even compile, to be more precise) since the local variables “first” and “second” are not initialized before they are used. A correct form would be :

[Test]
public void NullableInt() {
int? first = null;
Nullable second = null;
Assert.IsNull(first);
Assert.IsNull(second);
}

Otherwise a GREAT book!

199TYPO

In the footnote there’s a reference to [Sub05] which I can’t seem to find anywhere in the book.
The footnote says:
1For more on garbage collection “gotchas”, see [Sub05].

2009-12-09

Categories: