Joe White’s Blog

Life, .NET, and Cats


Archive for June, 2008

Low-lock multithreading

Wednesday, June 25th, 2008

I ran across a great article about how to do multithreading without (or with very few) locks.

If you’ve done concurrency, you already know about locks. You probably also know they’re expensive, and you’ve probably wondered how to squeeze out more performance by avoiding locks. This article tells you how to do it safely — and, more importantly, when to avoid it (which is most of the time).

Memory Models: Understand the Impact of Low-Lock Techniques in Multithreaded Apps

Warning: this is hardcore geek stuff. I think I understood more than half of it.

Here’s the executive summary: Low-lock multithreading is hard. If you don’t understand everything in the article up to and including a given technique, don’t use it. Processor caches and read and write reordering make it more complicated than you thought it was. (Don’t take my word for it — read the first half of the article, before he even starts outlining the first technique.)

He didn’t say it in the article, but I’ll add my two cents: Never optimize anything (including adding low-lock techniques) until you’ve run a profiler and proven that you know where the bottleneck is. Any optimization without a profile is premature optimization.

Always remember M. A. Jackson’s Two Rules of Optimization:

  • Rule 1: Don’t do it.
  • Rule 2 (for experts only): Don’t do it yet.

TechEd 2008 notes: Evolving Frameworks

Sunday, June 15th, 2008

This session was aimed at people who write frameworks: low-level code used by thousands of people. When you’re writing a low-level framework, you have to be very cautious about how you change APIs, lest you break code in the field. If nobody outside your department consumes your code, and you compile all your code every time you build — probably the most common case — then most of this stuff is only of academic interest to you. But it’s interesting nonetheless.

This is my last session-notes post about TechEd 2008. I’ll probably post more about the con later — I think it’d be interesting, for example, to contrast the philosophies different presenters had about unit-testing best practices — but it’ll probably be a few days or weeks before I get back to that; writing 22 blog posts that are up to my own editorial standards is a lot of work, and I need a break!

Once again, those of you reading via DelphiFeeds are only getting the posts about general programming topics. If you want to also see the ones about features not likely to be directly relevant to Delphi anytime soon (e.g., lambda expressions, expression trees, LINQ, .NET-style databinding, add-ins, F#, the Provider pattern), you can look at my entire list of TechEd 2008 posts.

Evolving Frameworks
Krzysztof Cwalina
Program Manager, .NET Framework team
Microsoft

Team has dual charter:

  • Basic APIs (used to be on BCL team, now on higher-level application model, cross-cutting features)
  • Architectural and design quality of the whole framework
  • Framework produced by many (over 1,000) people. Goal to make it look like it was designed by one person. Consistency guidelines.
  • More recently looking into evolving APIs and improving the evolution process.

Frameworks deteriorate over time

  • OO design community has already done much research into how to change requirements
  • It’s even worse with APIs
  • Still many forces require changes over time
    • Requirements change
    • Ecosystem changes: new tools, language changes
    • People change

No silver bullet. But there are some techniques to design APIs that will be easier to evolve, and some tricks that allow modifications that used to be breaking.

Slow down framework deterioration

  • With thoughtful architecture
  • With proper API design (micro-design guidelines)
  • With framework evolution idioms

Libraries, Abstractions, Primitives

  • Three different kinds of types in frameworks

Library types

  • Definition: types that are not passed between components. Instantiate, use, then maybe keep a reference or maybe let the GC collect it.
  • Examples: EventLog, Debug.
  • Easy to evolve: leave old in, add new one.
  • Cost to consumers, of introducing duplication, is nonzero. Shouldn’t be done lightly, but is doable.

Primitive types

  • Definition: types that are passed between components and have very restricted extensibility (i.e., no subtype can override any members).
  • Examples: Int32, String, Uri
  • Hard to evolve
  • Little need to evolve. Usually very simple. Not much policy went into designing them.

Abstractions

  • Definition: types that are passed between components and support extensibility (i.e., interfaces or classes with members that can be overridden)
  • Examples: Stream, IComponent
  • Lots of policy; contracts usually quite strict
  • Hard to evolve
  • Unfortunately, there’s quite a bit pressure to evolve abstractions
  • Extremely difficult to design abstractions out of the blue
    • The most successful abstractions in the .NET Framework are those that have been around for many years
    • “What should a stream do?” is pretty well established.
    • Interface with too few members won’t be useful. Interface with too many members will be hard to implement.

Evolving libaries

  • Can write a new class and tell people to start using it. Problematic if there isn’t a good migration path.
  • Architecture
    • Dependency management
  • Design
  • Toolbox
    • Type forwarders — lets you move a type from one assembly to another without breaking binary compatibility
    • EditorBrowsableAttribute
    • ObsoleteAttribute
  • Some people say a library should be at least 10 times better before you should consider replacing the old one.

Dependency management

  • Mostly applicable to APIs with more than one feature area, esp. if they evolve at a different pace or are used for different scenarios.

Framework Layering

  • Within each layer, have “components” (groups of classes) that each evolve together
  • Manage dependencies between the components
  • Lower layers shouldn’t depend on higher layers

Basics of dependency management

  • API dependency: A depends on B if a type in B shows in the publicly accessible (public or protected) API surface of a type in A. Might be parameter type, base type, even an attribute.
  • Implementation dependency: type in A uses a type in B in its implementation.
  • Circular dependency (including indirectly)
  • Dependency going to a lower layer: OK
  • Dependency going to a higher layer: Not allowed
  • Dependency within a layer: discussed by architects to see if it makes sense

Design principles

  • Focus on concrete customer scenarios
    • Much easier to add to something simple
    • Does this minimal component meet your needs?
  • Keep technology areas in separate namespaces
    • Mainly applies to libraries
    • Single namespace should be self-contained set of APIs that evolve on the same time schedule and in the same way
  • Be careful with adopting higher level APIs (usually libraries) for lower layers
    • E.g., Design a high-level API, then realize you can make it general, so you try to move it to a lower layer.
    • This rarely works when it’s not thought through from the beginning.
    • Don’t do it just because you can.
  • Don’t assume that your library is timeless
    • XML DOM should not be in System.Xml namespace

Toolbox: Type forwarders

[assembly:TypeForwardedTo(typeof(SomeType))]
  • Lets you move a type to a different assembly without breaking already-compiled code
  • Put in assembly where the type used to be
  • Forces a compile-time dependency on the assembly the type has been moved to
    • Can only be used to move a type down?

Toolbox: ObsoleteAttribute

[Obsolete(...)]
public void SomeMethod() {...}
  • Take the API out of developers’ minds. Present simplified view over time of “This is the framework”.
  • Caution: many people think Obsolete is non-breaking, but that’s not entirely true because of “Treat warnings as errors”.
    • “Yes,” you may say, “but that’s only when you recompile.” True, but some application models, like ASP.NET, recompile on the fly.

Toolbox: EditorBrowsableAttribute

[EditorBrowsable(EditorBrowsableState.Never)]
  • Hides from Intellisense, but you can still use it without warnings.
  • Often this is good enough.

Evolving primitives

  • Minimize policy (keep them simple)
    • Int32 should be no more than 32 bits on the stack
  • Provide libraries to operate on primitives
    • Consider using extension methods to get usability

Extension methods and policy

// higher level assembly (not mscorlib)
namespace System.Net {
    public static class StringExtensions{
        public static Uri ToUri(this string s) {...}
  • Policy-heavy implementation in a library that’s isolated from the primitive
  • High usability because it’s an extension method

Evolving abstractions

  • HARD!
  • Plan to spend ~10x as long designing abstractions as you do designing policies or libraries
  • Right level of policy
  • Right set of APIs

Interfaces vs. abstract classes

  • Classes are better than interfaces from an evolution point of view
  • Can’t add members to interfaces, but can add them to classes
  • That’s why it’s Stream instead of IStream
  • Were later able to add timeouts to streams, and it was much easier to add than it would have been with an IStream.
  • Imagine that it had been IStream from the beginning, and later they’d decided to add timeouts.
    • Adding members to an existing framework interface is never allowed.
    • When adding timeout, would have had to make a new descendant interface ITimeoutEnabledStream.
    • Wouldn’t need CanTimeout.
    • Problem is, base types proliferate (e.g. Stream property on a StreamReader). So casts would proliferate as well. And your “is it the right type” is effectively your CanTimeout query.
    • Less usability, since new member doesn’t show up in Intellisense.

Summary

  • Primitives, abstractions, libraries
  • Dependency management
  • Controlling policy
  • API malleability
    • Classes over interfaces, type forwarders, etc.

Q&A:

Q: Have there been times you did an abstract class and later wished it had been an interface?
A: Really not yet; he’s still waiting to hear from a team who’s done a class and later wishes they hadn’t. There are some situations where you do need interfaces (e.g. multiple inheritance). Sometimes it’s still a judgement call.

Q: Guidance on when to use extension methods?
A: Working on some guidelines for the next version of the Framework Design Guidelines book. There are some proposed guidelines at LINQ Framework design guidelines (scroll down to section 2, then look for the list of “Avoid” and “Consider” bullet points); if those stand the test of time, they’ll eventually become official guidelines.

Q: When would you split a namespace into a separate assembly?
A: When you design assemblies and namespaces, they should be two separate design decisions. Feature areas have a high correlation with namespaces. Assemblies are for packaging, servicing, deployment, performance. Make the decisions separately.

Q: Why not fix design flaws when moving from 1.1 to 2.0?
A: As current policy, they don’t remove APIs. (Not promising that it will never happen.) They think they can evolve the framework in a relatively healthy way. They’re even brainstorming ways to add more things like type mappers, e.g. moving static methods from one type to another (but no, it’s not in a schedule). Didn’t have some of these mechanisms when they were writing 2.0.

Q: How does the CLR team resolve conflicts when reviewing a design? Consensus? Vote?
A: Many processes at MS revolve around “orb”. One for compatibility, one for side-by-side, etc. Groups of four roles: owner, participants, reviewers, approver (escalation point). Try to concentrate on owner and participants, to reach a conclusion by consensus. When that fails, go to the reviewers, then the approver. Approver rarely has to make the decision; more likely to educate than override.

Q: Long overloaded parameter lists vs. parameter objects?
A: They’ve done overloads in that case. Ideally, each shorter one just loses one parameter from a longer one (be consistent about ordering, etc.) Best if the leading parameters are similar, for Intellisense usability reasons. They do use parameter objects in a few cases, but mostly in cases where you don’t want to, or cannot, have overloads; e.g., an event. Also don’t want an interface with lots of overloads.

TechEd 2008 notes: How LINQ Works

Sunday, June 15th, 2008

How LINQ Works: A Deep Dive into the Implementation of LINQ
Alex Turner
C# Compiler Program Manager

This is a 400-level (advanced) talk about the implementation of LINQ.

  • What’s the compiler doing behind the scenes? Layers it translates down to
  • Differences between the translation in the object world vs. remote store

Example of LINQ syntax: GetLondoners()

var query = from c in LoadCustomers()
            where c.City == "London"
            select c;
  • They didn’t want to bake any knowledge of how to do queries into the compiler; instead they use libraries, so you could even use your own implementation of Where() if you really wanted to

Where() as it would look with .NET 1.x delegates:

bool LondonFilter(Customer c)
{
    return c.City == "London";
}
...
var query = LoadCustomers().Where(LondonFilter);
  • You don’t really want to make a new method for each filter
  • Solved in .NET 2.0 with anonymous delegates, but they were too wordy to encourage use of functional libraries
  • Rewritten with C# 3.0 lambdas:
var query = LoadCustomers().Where(c => c.City == "London");

Proving what it’s actually compiled to:

  • Use Reflector
  • In Reflector Options, set Optimization to “.NET 1.0”, so it doesn’t try to re-create the LINQ syntax for us
    • Interestingly, it does still show extension-method syntax and anonymous-type instantiations. Have to turn optimizations off entirely to see those, but then you’ll go crazy trying to read the code.
  • Anonymous delegates make:
    • A cache field with a wacky name and a [CompilerGenerated] attribute
    • A method with a wacky name and a [CompilerGenerated] attribute
    • Generated names have characters that aren’t valid in C# identifiers, but that are valid for CLR. Guarantees its generated names don’t clash with anything we could possibly write.
  • Implementing Where: you don’t really want to build a whole state machine. Use iterators instead:
static class MyEnumerable
{
    public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source, Func<TSource, bool> filter)
    {
        foreach (var item in source)
            if (filter(item)
                yield return item;
    }    
}
  • I didn’t realize .NET 2 iterators were lazy-initialized. Cool.

Side note: You can set a breakpoint inside an anonymous delegate, or on a lambda expression, even if it’s formatted on the same line of source code as the outer call. Put the cursor inside the lambda and press F9; I don’t think you can click on the gutter to set a breakpoint on anything other than the beginning of the line.

Side note: When you step into the c.City == "London" in the LINQ where clause, the call stack shows it as “Main.Anonymous method”.

var query = from c in LoadCustomers()
            where c.City == "London"
            select new { c.ContactName, c.Phone };
  • Anonymous type:
    • Generated with another C#-impossible name, and it’s generic.
    • Immutable.
    • Default implementations for Equals, GetHashCode, ToString.

LINQ to SQL: We don’t want to do any of this anonymous-delegate generation. Instead, want to translate the intent of the query into T/SQL, so the set logic runs on the server.

Side note: Generated NorthwindDataContext has a Log property. Set it to Console.Out and you’ll get info about the query that was generated for us.

Func<Customer, bool> myDelegate = (c => c.City == "London");
Expression<Func<Customer, bool>> myExpr = (c => c.City == "London");
  • The first is just a delegate.
  • The second is a parse tree.
    • C# samples have an Expression Tree Visualizer that you can download.
  • This runs a different Where method. That’s because here we’ve got an IQueryable<T>, rather than just an IEnumerable<T>.
  • Where() takes an Expression<Func<TSource, bool>> predicate. So the compiler generates an expression tree.
  • Where() just returns source.Provider.CreateQuery(...new expression...), where the new expression is a method call to itself, with parameters that, when evaluated, become the parameters it was called with. (Is your head spinning yet?) It basically just builds the expression-tree version of the call to itself, which is later parsed by LINQ to SQL and turned into an SQL query.
  • LINQ to Objects: code that directly implements your intent
  • LINQ to SQL: data that represents your intent

The difference is all in the extension methods.

Cedar Rapids’ Flood of 2008

Friday, June 13th, 2008

Absolutely unreal.

I was in Cedar Rapids for the Flood of ’93. I remember vividly one night when I drove a friend home, and on the way, we drove past a neighborhood park. There was a river coming out of the park, and flowing gently across the road. We couldn’t even see where the curb was supposed to be.

I had been planning to drop my friend off and head back home, but I changed my mind. I called my parents when I got there and said I was going to be spending the night.

The flooding now makes that look like a rain puddle.

None of my family live near the river, thankfully. Mom and Dad just have a trickle of water in their basement, and Jon and Darcy have damp carpet, nothing more.

But the public library where I used to work had water up to its windows yesterday afternoon, and the water was still rising. They never thought the water would get anywhere near that high, and by the time it did, it would have been far too late to start moving books upstairs — you couldn’t even get near the building anymore. It breaks my heart to think of all the damage to those books, historical records, everything. Not to mention the library itself — the city keeps cutting the library budget, to the bone and beyond, and I don’t know how they’re going to get the funding to repair the damage. I pray they have flood insurance, but I wouldn’t count on it.

Flood stage is 13 feet, but the levees are built to handle 19 feet of water. The river hit 20 feet in the Flood of ’93. This time around, the river is expected to crest at 32 feet. No typo.

I spent over an hour watching news coverage online last night. KCRG TV-9 had been doing “wall-to-wall” news coverage most of the day — no programming, no commercials, no interruptions, just news. It doesn’t look like they’re newscasting this morning, and I wonder if they had to evacuate their news studio — they were inside the mandatory evacuation area, and last night they had gotten special permission to stay, because they’re providing a public service, but they were keeping a close eye on conditions and ready to leave if they had to.

Absolutely unreal. May’s Island isn’t there — just a City Hall sticking up out of the water. The police office and jail had to be evacuated. The downtown Dairy Queen is totally submerged. 8,000 people were evacuated from neighborhoods near the river, and firefighters (in boats) were rescuing the idiots who ignored the mandatory evacuation. Video footage of boats going under the downtown skywalks. The railroad trestle collapsing, despite the 20 railroad cars filled with rocks that were left on the trestle to try to weight it down. Downtown a lake. One of the emergency shelters full — sounds like they’ve got cots filling the hallways. People at the shelters having to leave their pets in the cars outside, because the shelters couldn’t accommodate any animals other than service animals. Over 14,000 people without power, and the word is they’ll probably be without power for a week. Power out as far out as Coe College, over a mile from the river. I think it was Coralville where power was out and they couldn’t even get to the power station to start repairing the damage. Part of I-80 closing, east of Iowa City — that’s a major transportation route, and it’ll hurt. Only one bridge in CR open, and that’s I-380, and traffic moving at a crawl because there’s only one through lane open each direction — other lanes reserved for emergency vehicles. People stopping their cars on I-380 to gawk and take pictures. (The news crew said, “Don’t. We can guarantee, we’ve got better cameras than you do.”) The city’s water supply down to 25% of capacity, because three of the four wells are underwater; people being asked to use drinking water only; people being asked to come out to fill sandbags to protect the remaining well (no longer needed — that effort is complete). The library, the Czech museum, the museum of art, the Science Station — all flooded. One of the two hospitals evacuated. Both hospitals without power, running on generators.

It’s hard to swallow. And it’s really hard, right now, to be so far from home.

TechEd 2008 notes: How not to write a unit test

Thursday, June 12th, 2008

How not to write a unit test
Roy Osherove
Typemock
Blog: ISerializable.com

All the things no one ever told you about unit testing.

Will have two parts: presentation-like (what really works), and interactive (questions, prioritized).

Early questions:

  • Data access
  • Legacy code (what not to do)
  • Duplication between unit tests and functional tests
  • Testing non-.NET code, e.g. ASP.NET
  • Testing other languages, e.g. F#, IronRuby)
  • Unit tests and refactoring
  • Testing UI
  • How do you mock the world?
  • How important are tools? Mocking tools, refactoring, etc. Can you write unit tests with just what VS provides?
  • Did you bring your guitar? — No. Wanted as much time for information as possible.
  • Where did you get your T-shirt? — Was being given away at another conference.

A unit test is a test of a small functional piece of code

  • If a method returns a boolean, you probably want at least two tests

Unit testing makes your developer lives easier

  • Easier to find bugs.
    • That’s the common line. But not necessarily — e.g. if your test has bugs, or if you’re testing the wrong things
    • If you can’t trust your tests to find bugs (and especially if you don’t know you can’t trust them), then the opposite may be true — you may be confident you don’t have bugs when you do.
    • If you don’t trust them, then you won’t run them, they’ll get stale, and your investment in writing them was wasted.
  • Easier to maintain.
    • But 1,000 tests = 1,000 tests to maintain
    • Change a constructor on a class with 50 tests — if you didn’t remove enough duplication in the tests, it will take longer than you think to maintain the tests
    • We will look at ways to make tests more maintainable
  • Easier to understand
    • Unit tests are (micro-level) use cases for a class. If they’re understandable and readable, you can use them as behavior documentation.
    • Most devs give really bad names to tests. That’s not on purpose.
    • Tests need to be understandable for this to be true.
  • Easier to develop
    • When even one of the above is not true, this one isn’t true.

Make tests trustworthy

  • Or people won’t run them
  • Or people will still debug for confidence

Test the right thing

  • Some people who are starting with test-driven development will write something like:
[Test]
public void Sum()
{
    int result = calculator.Sum(1, 2);
    Assert.AreEqual(4, result, "bad sum");
}
  • Maybe not the best way to start with a failing test
  • People don’t understand why you want to make the test fail
  • Test needs to test that something in the real world is true: should reflect the required reality
  • Good test fails when it should, passes when it should. Should pass without changing it later. The only way to make the test pass should be changing production code.
  • If you do TDD, do test reviews.
    • Test review won’t show you the fail-first. But you can ask, “So can you show me the test failing?”

Removing/Changing Tests

  • Don’t remove the test as soon as it starts passing
    • If it’s a requirement today, chances are it’ll still be a requirement tomorrow
    • Duplicate tests are OK to remove
    • Can refactor a test: better name, more maintainability
  • When can a test fail?
    • Production bug — right reason (don’t touch test)
    • Test bug (fix test, do something to production code to make the corrected test fail, watch it fail, fix production code and watch it pass)
      • Happens a lot with tests other people wrote (or with tests you don’t remember writing)
    • Semantics of using the class have changed (fix/refactor)
      • E.g., adding an Initialize method that you have to call before you use the class
      • Why did they make that change without refactoring the tests?
        • Make a shared method on the test class that instantiates and Initializes
    • Feature conflict
      • You wrote a new test that’s now passing, but the change made an old test fail
      • Go to the customer and say, “Which of these requirements do you want to keep?”
      • Remove whichever one is now obsolete

Assuring code coverage

  • Maybe unorthodox, but Roy doesn’t like to use code-coverage tools
    • 100% code coverage doesn’t mean anything. Finds the exceptions, but doesn’t prove the logic.
  • Better: change production code and see what happens
  • Make params into consts
  • Remove “if” checks — or make into consts (if (true)). Will a test fail? If not, you don’t have good coverage.
  • Do just enough of these kinds of tweaks to make sure the test is okay.
  • Test reviews are still valuable if you do pair programming, just maybe less often. Good to bring in someone else who didn’t write the code, with an objective eye.
  • Quick test review of yesterday’s code at end of stand-up meeting?

Avoid test logic

  • No ifs, switches or cases
    • Yes, there are always exceptions, but it should be very rare
    • Probably only in testing infrastructure
    • Most of the time, there are better ways to test it
    • Sometimes people write conditionals when they should be writing two tests
    • Don’t repeat the algorithm you’re testing in the test. That’s overspecifying the test.
  • Only create, configure, act and assert
  • No random numbers, no threads
  • Test logic == test bugs
  • Fail first also assures your test is correct

Make it easy to run

  • Integration vs. Unit tests
  • Configuration vs. ClickOnce
  • Laziness is key
  • Should be able to check out, run all the unit tests with one click, and have them pass.
  • Might need to do configuration for the integration tests, so separate them out.
  • Never check in with failing tests. If you do, you’re telling people it’s okay to have a failing test.
  • Don’t write a lot of tests to begin with, and have them all failing until you finish everything. If you do that, you can’t check in (see previous point). Write one test at a time, make it pass, check in, repeat.

Creating maintainable tests

  • Avoid testing private/protected members.
    • This makes your test less brittle. You’re more committed to public APIs than private APIs.
    • Testing only publics makes you think about the design and usability of a feature.
    • Publics are probably feature interactions, rather than helpers.
    • Testing privates is overspecification. You’re tying yourself to a specific implementation, so it’s brittle, and makes it hard to change the algorithm later.
    • Sometimes there’s no choice; be pragmatic.
  • Re-use test code (Create, Manipulate, Assert) — most powerful thing you can do to make tests more maintainable
  • Enforce test isolation
  • Avoid multiple asserts

Re-use test code

  • Most common types:
    • make_XX
      • MakeDefaultAnalyzer()
      • May have others: one already initialized, with specific parameters, etc.
    • init_XX
      • Once you’ve already created it, initialize it into a specific state
    • verify_XX
      • May invoke a method, then do an assert on the result. Pulling out common code.
  • Suggestion: by default, the word new should not appear in your test methods.
    • As soon as you have two or more tests that create the same object, you should refactor the new out into a make method.

Suggestion: don’t call the method directly from Assert.AreEqual(...). Introduce a temp variable instead. (This relates back to the 3A test pattern.)

Aside: Test structure

  • One possibility: Each project, e.g. Demo.Logan, has tests Demo.Logan.Tests. Benefit: they’re next to each other in Solution Manager.
  • Test files: one file per tested class?
    • That’s a good way to do it. Aim for a convention like MyClassTests so it’s easy to find.
    • If you have multiple test classes for one test, make multiple classes.
    • Consider nested classes: making a MyClassTests, and putting nested classes, one per feature. Make the nested classes be the TestFixtures.
      • Be careful of readability, though.
      • Roy said his preference would be to keep one test class per source file, rather than using nested classes to put them all in one file.
      • Decide for yourself whether you’d prefer one class per file, or all tests for one class in one place.

Enforce test isolation

  • No dependency between tests!
  • If you run into an unintended dependency between tests, prepare for a long day or two to track it down
  • Don’t run a test from another test!
  • You should be able to run one test alone…
  • …or all of your tests together…
  • …in any order.
  • Otherwise, leads to nasty “what was that?” bugs
  • Almost like finding a multithreading problem
  • The technical solution (once you find the problem) is easy. That’s why God created SetUp and TearDown. Roll back any state that your test changed.

Avoid multiple asserts

  • Like having multiple tests
  • But the first assert that fails — kills the others. If one test fails, the others still run. Asserts aren’t built that way.
  • Exception: testing one big logical thing. Might have three or four asserts on the same object. That’s possible, and doesn’t necessarily hurt.
  • Consider replacing multiple asserts with comparing two objects (and also overriding ToString so you can see how they’re different when the test fails).
    • My experience: this doesn’t work well when the objects get really big and complicated. Could work well for small objects, though.
  • Hard to name
  • You won’t get the big picture (just some symptoms)

Don’t over-specify

  • Interaction testing is risky
  • Stubs -> rule. Mocks -> exception.
  • Mocks can make you over-specify.
  • “Should I be able to use a stub instead of a mock?”
    • A stub is something you never assert against.
  • There’s only one time when you have to use mocks: when A calls a void method on B, and you have no way to later observe what B was asked to do. Then you have to mock B and verify that it was called with the right parameter.
    • If the other class does return a value, then you can test what your class did with that result. You’re testing your class, after all, not that other object — that’s why you’re faking it.

Readability

  • If you do another test that tests basically the same thing, but with different parameters, he suggests appending “2” to the end of the test name. But that’s assuming you already have a really good naming convention for the base test name! (Remember the serial killer.)
  • Bad: Assert.AreEqual(1003, calc.Parse("-1"));
  • Better:
int parseResult = Calc.Parse(NEGATIVE_ILLEGAL_NUMBER);
Assert.AreEqual(NEGATIVE_PARSE_RETURN_CODE, parseResult);
  • If you can send any kind of number, and the specific value you pass doesn’t matter, either use a constant, or use the simplest input that could possibly work (e.g. 1).

Separate Assert from Action

  • Previous example
  • Assert call is less cluttered

TechEd 2008 notes: Best Practices with the Microsoft Visual C# 3.0 Language Features

Thursday, June 12th, 2008

Still catching up on posting my notes from TechEd last week. I probably would’ve gotten this up last night if I hadn’t been in the basement most of the evening for tornado warnings.

Best Practices with the Microsoft Visual C# 3.0 Language Features
Mads Torgersen
Program Manager for the C# Language
Microsoft

He’s the guy who figures out what features go in the next version of the language, to keep us on our toes.

Goals of this talk

  • Show new features
  • Important do’s and don’ts
  • Introduce LINQ

Despite the name of the talk, more time will be given to C# 3 features than to best practices. Best practices are in there, but they’re not the star of the show. If you’re going to be annoyed by that, start being annoyed now, rather than waiting until the end.

C# 3 in a Nutshell

  • Imperative => Declarative
    • Before: modify state in little bits
    • Leads to a lot of detail in describing how you want things done
    • New: say what you want, rather than how you want it done
    • MS has freedom to give us performance and flexibility

  • How => What
  • Make queries first-class

(Incomplete) list of new features

  • Auto properties
  • Implicitly typed locals
  • Object and collection initializers
  • Extension methods
  • Lambda
  • Queries
  • Anonymous types
  • Expression types
  • …a couple not shown in this talk

Automatically Implemented Properties

  • Just sucking up to programmers’ laziness; nothing deep
class Customer
{
    public string CustomerID { get; set; }
    public string ContactName { get; set; }
}
  • Simplify common scenario
  • You can see that they’re trivial
  • Limitations
    • No body -> no breakpoints
    • No field -> no default value
  • There can be serialization issues if you change an automatic property to a real property, since the autogenerated field has a magic name that’s stored in your serialized data

Lure of Brevity: Best practices for auto properties

  • Only use this for things that really are simple get/set properties
  • Hold on to your…
    • Get-only and set-only properties
    • Validation logic
  • Private accessors (get; private set;) are usually not the answer — too easy to forget you didn’t intend for them to be set capriciously, and add code a year from now that sets them in an unsafe way
  • Be careful what you make settable:
// Bad
class Customer {
    public string CustomerKey { get; set; }
    // Key really shouldn't be settable

Implicitly Typed Locals

  • var keyword, type inference
  • I won’t bother quoting his code snippet, you’ve seen it before
  • Intellisense can show you the actual type — hover over the var
  • Remove redundancy, repetition, clutter
  • Allow focus on code flow
  • Great for experimentation: you can change something’s return type and there’s a much better chance that everything will still compile (Roy would probably say there’s more essence and less ceremony)
  • “Surprisingly liberating experience”

Redundancy is not always bad: best practices for var

  • Explicit types on locals (i.e., not using var) will…
    • Improve readability of complex code, esp. if method name doesn’t make its return type clear
    • Allow typechecking on right-hand side (when you want that)
    • Can be more general than the right-hand side
  • Think: Who is the reader?
  • Find your own compromise between the two extremes

Side note: ObjectDumper class from samples (kind of like .inspect in Ruby)

Object and collection initializers

  • Traditionally very imperative. Start with empty collection, then create an empty Customer, then initialize it, then add it.
  • Lots of intermediate results lying around.
static IEnumerable<Customer> GetCustomers()
{
    var custs = new List<Customer>()
    {
        new Customer {
            CustomerID = "MADST",
            ContactName = "Mads Torgersen",
            City = "Redmond"
        }
    };
}
  • Can omit empty parens after new if you use an object initializer
  • Code-result isomorphism
    • Structure of code parallels structure of object you want.
  • Expression-oriented
    • Can be used in expression context
  • Atomic
    • No intermediate results
    • Create object and collection in one fell swoop. Don’t need temporary variables. Don’t expose any intermediate states at all.
  • Compositional
  • May not need as many constructor overloads

Constructors are still good: best practices for object and collection initializers

  • Constructors…
    • Show intent
    • Enforce initialization
    • Initialize get-only data
  • Initializers and constructors compose well
var c = new Customer("MADST"){
    ContactName = ...

Extension Methods

  • You’ve seen these demos too (well, maybe not GetLondoners() specifically)
  • Dilemma with very general types: you use them in a specific setting, and sometimes you want a special view on it and wish you could add a couple more methods to the original declaration, just for your use in that setting
  • One really interesting benefit: can add methods to a generic of only certain types, e.g. can have a method on IEnumerable<Customer> that isn’t there on the general IEnumreable<int>. I like this!
  • Declared like static methods, can call like instance methods
  • New functionality on existing types
  • Scoped by using clauses
  • Interfaces and constructed types

Cluttering your Namespace: best practices for extension methods

  • Consider making them optional (separate namespace), so people can use your library without necessarily needing your extension methods (extension methods for working with types from MyNamespace.Foo should be in their own namespace, not right in MyNamespace.Foo)
  • Don’t put them on all objects!
  • Make them behave like instance methods.
namespace System
{
    public static class MyExtensions
    {
        // Don't do this
        public static bool IsNull(this object o) {
            return o == null;
        }
    }
}
  • That’s a worst practice. It violates all three of the above guidelines. Don’t do it just because it’s cool.

Lambda Expressions

  • Predicate<T> — function that takes T and returns bool
  • =>: Some call this the “fat arrow”
  • Terse anonymous functions
  • Parameter types inferred from context
  • Closures: capture local state (also true of anonymous methods)

Condensed Power: best practices for lambda expressions

  • Keep them small
    • That’s the point of making them terse
    • Yank them out if they get too big
  • Watch that capture (of local variables, and using them inside the lambda)
    • Can have unexpected results
    • Exposing private state
  • Watch the complexity
    • Functions of functions returning functions…
  • Think: Who executes this lambda, and when?

Queries

  • Functional: doesn’t mutate the original collection; instead returns a new collection
  • using System.Linq; == “Linq to Objects”
  • Extension methods give you pipelining: customers.Where(...).Select(...)
  • Language integrated — use anywhere! (if you’re using C#)
  • Query expressions for common uses
  • Mix and match query and method syntax
  • Expect deferred execution (can do ToArray)

Beware monadic complexity hell: best practices for queries

  • Another powerful complexifier
  • Do you need to roll your own query provider?
  • Use query pattern for queries only!
    • Avoid abusing query syntax for other magic
    • Even if you know about monads! (Your users don’t)

Anonymous types

  • select new { Name = c.ContactName, c.City } — smart enough to call the second property City
  • Temporary local results
  • Shallow immutability and value equality
  • Does a nice job on the generated classes
    • Value-based equality
    • Good hashcodes

Keep it local: best practices for anonymous types

  • If you need a type, make one! Don’t use an anonymous type and work around problems. Only use where they don’t limit you.

Expression trees

  • Runtime object model of code
  • Created from lambda expressions
  • Language independent. LINQ to SQL doesn’t know about C#; it just knows about expression trees.
  • Compile back into delegates on demand. .Compile() method — even if you created it with factories instead of a lambda.

The Lure of Doing Magic: best practices for expression trees

  • You can interpret expression trees any way you like.
  • Don’t!
    • Stay close to expected semantics
    • Avoid special magic names, etc.

Final words

  • C# 3 and LINQ can change the way you code…
    • Declaratively: more of the what, less of the how
    • Eloquently
    • And with lots of queries. Don’t think of queries as something heavyweight for external data.
  • …but they don’t have to!

TechEd 2008 notes: Create Your Own Providers for the Ultimate Flexibility

Tuesday, June 10th, 2008

This was an interesting session. The Provider model seems simple enough. There’s a lot of classes involved, each of which is pretty simple (I think he stuck pretty well to the single-responsibility principle), although I had a bit of a hard time keeping track of which class went where in the chain. Sometime later I’ll look back at this and draw some sort of class-interaction diagram to help me figure it out.

One note, though: apparently there’s a ProviderBase class that does some of the boilerplate code for you. He didn’t mention that until the very end (after someone asked him about it). So this is mostly theory about the bits and pieces, rather than necessarily a list of what you need to implement on your own. I haven’t looked at ProviderBase to see how much of a base it gives you to build on.

Create Your Own Providers for the Ultimate Flexibility
Paul D. Sheriff
President
PDSA, Inc.

Samples at pdsa.com/teched, in both VB.NET and C#.

Agenda

  • What’s a provider and why use one
  • Dynamically loading assemblies
  • Creating a custom data provider
  • Implement an ASP.NET Membership provider
    • Store users/roles in XML file

What is a provider?

  • Components that can be loaded at runtime
  • Allows you to switch components without recompiling
  • Patterns
    • Strategy
    • Abstract factory

Why use a provider?

  • Keep dev API consistent
    • Developer always calls a method named SendAFax
  • Implementation can be different

Provider examples

  • ADO.NET Data Provider
    • MSSQL
    • Oracle
    • OLE DB
    • DB2
  • Each implements an interface
    • IDBCommand
    • IDBConnection
  • ASP.NET Membership System
    • Front end always same
      • Login control, CreateUserWizard control
    • User storage can change
    • Change the provider by deploying a new DLL (not recompiling old) and changing the config file
  • ASP.NET session state

How to…

  • Create interfaces and/or base classes
  • Dynamically load
  • Read config files
  • Create providers

Dynamically create the class

  • System.Type.GetType(className)
  • System.Activator.CreateInstance(type)

Dynamically load assembly

  • Assembly class
    • Use Load if in GAC or current directory
    • Use LoadFile if not
  • Then use the Assembly‘s CreateInstance

Reading the config file

  • ConfigurationManager.AppSettings[“ProviderName”]
  • Better: add your own section. But that’s a little more work.

Demo

<configuration>
  <configSections>
    <section name="ConfigSettings" type="ConfigSimple.ConfigSectionHandler, ConfigSimple">
  </configSection>
  <ConfigSettings type="..." location="...">

class ConfigSectionHandler : ConfigurationSection
{
    [ConfigurationProperty("type")]
    public string Type
    {
        get { return (string) this["type"]; }
    }
    [ConfigurationProperty("location")]
    public string Location
    {
        get { return (string) this["location"]; }
    }
}
abstract class ConfigProviderBase
{
    public abstract string GetSetting(string key);
    public string Location { get; set; }
}
class ConfigSettings
{
    private static ConfigProviderBase _configProvider;
    private static void InitProvider()
    {
        object section = ConfigurationManager.GetSection("ConfigSettings");
        ConfigSectionHandler handler = (ConfigSectionHandler) section;
        _configProvider = (ConfigProviderBase)
            Activator.CreateInstance(Type.GetType(handler.Type));
        _configProvider.Location = handler.Location;
    }
    public static string GetSetting(string key)
    {
        if (_configProvider == null)
            InitProvider();
        return _configProvider.GetSetting(key);
    }
}

So, here’s provider #1:

class ConfigAppSettings : ConfigProviderBase
{
    override string GetSetting(string key)
    {
        return ConfigurationManager.AppSettings[key];
    }
}

And, another one that reads from a separate XML file instead:

class ConfigXML : ConfigProviderBase
{
    public override string GetSetting(string key)
    {
        string result = "";
        var xe = XElement.Load(this.Location);
        var setting = (from elem in xe.Elements["Setting"]
            where elem.Attribute("key").Value == key
            select elem).SingleOrDefault();
        if (setting != null)
            result = setting.Attribute("value").Value;
        return result;
    }
}

Could have used a whiteboard with some boxes and arrows, because it seems like the naming conventions are confusing. But it’s just a matter of following the pattern.

Has an example of how to do this with a collection of providers specified in the XML (e.g., <providers> <add ... /> <add ... /> <add ... /> </provider>)

Once you start the process, get the boilerplate going, writing a new provider becomes pretty easy.

TechEd 2008 notes: Advanced Unit Testing Topics

Tuesday, June 10th, 2008

He repeated a lot of his favorite patterns that I already took notes about in his earlier session, “Design and Testability“. If you haven’t read that one yet, go check it out.

Advanced Unit Testing Topics
Ray Osherove
Typemock
Blog: http://iserializable.com/

The Art of Unit Testing (book he’s working on)

Assumption for this session: You have some experience with writing tests

Mocking 101

  • Replace dependencies with fakes so you can test something
  • If the Storage class calls a non-virtual void method on EmailSender, you can’t test that interaction.
  • Pass an interface instead of a class. “Dependency injection”. Then we can write a FakeEmailSender and pass that in, and it can do whatever we want.
    • Do nothing
    • Set a flag saying “I got asked to send the e-mail”
  • Can create the fake manually or with a mock-object framework
  • Fake vs. mock
    • Fake: fake to make the system more testable. They won’t fail your test. (In another session, I heard this called a “stub”, with “fake” as a top-level term for both stubs and mocks.)
    • Mock: something we will assert against. These can be used to detect conditions where your test should fail.
  • More complex scenario: force EmailSender to throw an exception, so you can test how StorageManager interacts with ILogWriter.
    • FakeEmailSender, FakeLogWriter — where the LogWriter is a mock (you’ll assert that it actually got asked to log the error), and the e-mail sender is a fake (you don’t assert against it, it just replaces the real one)
    • Usually, in a test, you’ll only have one mock, and maybe many fakes

Side note: Test names should be extremely readable. Imagine that the person reading your code is a serial killer who knows where you live. Don’t make him mad.

Mock-object libraries

TypeMock:

[Test]
[VerifyMocks]
public void Typemock_Store_StringContainsStar_WritesToLog()
{
    ILogger log = RecorderManager.CreateMockedObject(typeof(ILogger));
    // Tell the mock object what you expect to happen in the future
    using (var r = new RecordExpectations())
    {
        log.Write("*");
        // Tell it to check parameter values, rather than just expecting
        // the method to be called
        r.CheckArguments();
    }
    // Now run the code under test
    var sm = new StorageManager(log);
    sm.Store("*");
}
  • The assert isn’t in the code — it’s implicit in the [VerifyMocks] attribute. Can also do it explicity through a method call.

RhinoMocks:

[Test]
public void Typemock_Store_StringContainsStar_WritesToLog()
{
    MockRepository mocks = new MockRepository();
    ILogger log = mocks.CreateMock();
    using (mocks.Record())
    {
        log.Write("*");
        // RhinoMocks checks arguments by default.
    }
    // Now run the code under test
    var sm = new StorageManager(log);
    sm.Store("*");
}
  • Looking back at that, I wonder if I missed something, because I don’t see any sort of VerifyMocks() call in that code snippet. I probably missed copying it down from the slide.

What happens when you can’t extract an interface?

  • Derive from the class under test

What happens when you can’t change the design?

  • Can cry to our managers
  • Typemock lets you mock things that are static or private, without modifying the design.
    • So suppose the Storage class instantiates the Logger itself, and you can’t change it. How do you break the dependency so you can test the code?
[Test]
[VerifyMocks]
public void Typemock2_Store_StringContainsStar_WritesToLog()
{
    using (var r = new RecordExpectations())
    {
        new Logger().Write("*");
        r.CheckArguments();
    }
    var sm = new StorageManager2();
    sm.Store("*");
}
  • Yep, it can record, and later fake out, a new call.
  • Uses the .NET Profiling API to do this. Deep black magic.

Mock object frameworks save time and coding, but sometimes fake objects are the simpler solution

Testing ASP.NET WebForms

  • Integration testing: use tools that invoke the browser and check stuff out
  • To test it in-process, and fake out the HttpContext and all that: Ivonna (which uses Typemock underneath)
    • Lets you set values on controls, and then process postbacks in-process

Extending the test framework with extension methods

  • Create a domain-specific language on your objects
"abc".ShouldMatch("\\w");
List<int> ints = new List<int> { 1, 2, 3, 4, 5, 6 };
ints.ShouldContain(4);
3.ShouldBeIn(ints);
5.ShouldBeIn(ints);
  • Make a static class with static methods
  • First parameter has this
  • Call asserts from the extension method
  • Import the namespace in order to be able to use the extension methods
public void ShouldBeIn(this object o, IEnumerable items)

Testing (and Mocking) LINQ Queries

  • LINQ is not a test-enabling framework by default
  • Use Typemock, then duplicate the LINQ query in your test (to record the calls)
  • The problem is, you’re over-specifying your tests, because you have to know what query is being run underneath — you’re specifying the internal behavior
  • So, avoid doing this unless you have to
  • May be better to abstract away the queries
  • What about projections? E.g. selecting an anonymous type?
    • Typemock can record anonymous types. He already had a demo for this.
    • Can be really, really weird.
using (RecordExpectations rec = new RecordExpectations())
{
    var p1 = new { Name = "A", Price = 3 };
    rec.CheckArguments();
    string a = p1.Name;
    rec.Return("John");
}
var target = new { Name = "A", Price = 3 };
Assert.AreEqual("John", target.Name);
  • The above actually passes. Yes. Look closer. They’re mocking the return value of the anonymous type, so even though you construct it with “A”, it returns “John”. Like I said above, deep black magic.

Testing WCF

  • Again, maybe the best thing is not to unit-test it. Consider an integration test instead.
  • Integration test: create a ServiceHost, ChannelFactory
    • Still might want to use Typemock for things like the security context
    • Be pragmatic about things. If it’s one line of code to use Typemock, vs. introducing lots of interfaces, maybe it’s worthwhile (as long as it’s maintainable).
  • Worth making a WCFTestBase<T, TContract> to pull out common code.
    • If you do integration testing, get used to base test-fixture classes to remove duplication.

Database-related testing

  • To mock or not to mock the database?
    • Mock:
      • Tests will be fast, no configuration, don’t need a real database.
      • But the database itself also has logic. Keys, indexes, integrity rules, security, triggers, etc.
  • Team System has a tool for testing against databases, but it’s not really “there” yet.
  • Can do an integration test against the database.
  • If you change external data, roll back between tests. Good solution: lightweight transactions with TransactionScope. Create in SetUp (with TransactionScopeOption.RequiresNew), and call Dispose in TearDown.
    • Will work even if the test creates its own transaction (as long as it doesn’t also do RequiresNew).

Put integration tests in a separate project, so it’s easy to run the unit tests (which are fast) all the time, without being slowed down by the integration tests (which are slow, require configuration, etc.)

Testing events

  • Hook the event as usual
  • Hook it with an anonymous delegate
  • Do your asserts inside that anonymous delegate
  • Make an eventFired variable and set it true from inside the delegate
  • Assert eventFired in the main test body
  • Yay closures!

Musical postlude

TechEd 2008 notes: Lessons Learned in Programmer (Unit) Testing

Monday, June 9th, 2008

This one was a mixed bag. Some of his lessons learned are worth looking at, like the 3A pattern, and he covered classics like inversion of control and avoiding ExpectedException. But he was pretty dogmatic about a couple of things that just didn’t make much sense.

Lessons Learned in Programmer (Unit) Testing: Patterns and Idioms
James Newkirk, CodePlex Product Unit Manager

Been writing software for close to 25 years.
When he was first hired after college:

  • Company made EEs work in manufacturing for 2 years
    • Goal: teach them how to build things that could be manufactured
  • Software people just started writing stuff
    • Never taught how to build things that were testable, maintainable. Up to them to discover that.

JUnit Test Infected: Programmers Love Writing Tests
(Has anyone actually met programmers who love writing tests?)

  • Programmers weren’t writing tests
  • Couldn’t prove that what they had worked
  • James ported JUnit to .NET as NUnit, released as open-source
  • How can we use open-source to enable different kinds of innovation?

“Unit testing” means something to testing people. Some think, if cyclomatic complexity is 5, then I need 5 unit tests. Not the same thing as tests for test-driven development. So we’ll probably not use the term “unit test”.

What is programmer testing? Per Brian Marick

  • Technology vs. Customer
  • Support vs. Critique
  • Support + technology: Programmer tests
  • Support + customer: Customer tests
  • Critique + customer: Exploratory tests (should still happen during the development process)
  • Critique + technology: “ilities” — non-functional. Scalability, usability, performance, etc.

Why do programmer testing?

  • “There is no such thing as done. Much more investment will be spent modifying programs than developing them initially.” [Beck]
    • Whenever we think we’re finished, we’re probably wrong. There can always be more features.
    • Can define “done” locally: “We’re done with this release.”
    • Programmer testing lets me say as a programmer, “I believe that I am done.”
  • “Programs are read more often than they are written.” [Beck, “Implementation Patterns” book]
    • You’re writing a book on your code.
    • The only artifact of any value is the code. It has to be the communication mechanism.
  • “Readers need to understand programs in detail and concept.” [Beck]

Total development cost:

  • Develop (illustrated in green): small. Fun!
  • Extend/Maintain (orange): big. Sucks, especially if you didn’t write the green part!

“I might break something!”

  • Fear lowers our productivity
    • Programmer tests help, because if you broke something, you know. You know the consequences of your actions.
  • Where do I start?
    • Programmer tests are very useful in this understanding phase

Lesson #1: Write tests using the 3A pattern

  • Attributed to Bill Wake (xp123.com)
    • Arrange — Set up the test harness
    • Act — Run the thing you actually want to test
    • Assert — Verify the results
[Fact]
public void TopDoesNotChangeTheStateOfTheStack()
{
    // Arrange
    Stack<string> stack = new Stack<string>();
    stack.Push("42");
    
    // Act
    string element = stack.Top;
    
    // Assert
    Assert.False(stack.IsEmpty);
}
  • Benefits
    • Readability
    • Consistency
  • Liabilities
    • More verbose
    • Might need to introduce local variables
  • Related issues
    • One assert per test?
      • Much agile dogma says there should only be one assert
      • Pragmatic view: test should only test one thing, but if that one thing takes multiple asserts, that’s fine

Lesson #2: Keep your tests close

  • Tests should be as close as possible to the production code
  • Same assembly?
  • Treat them like production code
  • They have to be kept up-to-date
  • Visibility (let you see internal)
    • (I would argue that, if you think you need to test your internal state, what’s really going on is that you’ve got another object that wants to get out.)
  • Liabilities
    • Should you ship your tests?
      • If so, you need to test your tests. Whole new level.
      • Need to make sure your tests don’t modify the state of the system
      • If No, how do you separate the tests from the code when you release?
    • Various tool issues

Lesson #3: ExpectedException leads to uncertainty

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PopEmptyStack()
{
    Stack<string> stack = new Stack<string>();
    stack.Pop();
}
  • Problem #1: where’s the assert? A: it’s in the framework. Violates 3A.
  • Obfuscates the test to some extent.
  • Better:
[Fact]
public void PopEmptyStack()
{
    Stack<string> stack = new Stack<string>();
    Exception ex = Record.Exception(() => stack.Pop());
    Assert.IsType(ex);
}
  • Makes the exception more explicit.
  • Lets you inspect the exception object.
  • Another possibility is NUnit’s Assert.Throws():
[Fact]
public void PopEmptyStack()
{
    Stack<string> stack = new Stack<string>();
    Assert.Throws<InvalidOperationException>(delegate {
        stack.Pop(); });
}
  • Downside: Act and Assert are in the same spot.
  • Other problems with ExpectedException:
    • Don’t know which line of code threw the exception. Test can pass for the wrong reason. (This, IMO, is the most compelling reason to avoid ExpectedException.)
    • ExpectedException forces people to use TearDown. With Record.Exception or Assert.Throws, you can keep the teardown in the test if you like.

Alternatives to ExpectedException

  • Benefits
    • Readability
    • Identify and isolate the code you expect to throw
  • Liabilities
    • Act and Assert are together in Assert.Throws
    • Anonymous delegate syntax leaves something to be desired

Lesson #4: Small fixtures

  • Your code should be a book for people to understand
  • If the fixture has 1,000 tests, it’s hard for someone to know where to start
  • Better: fixtures focused around a single activity
    • Maybe even a fixture for each method
    • Can use nested classes for this. Outer class is named for the class you’re testing, with nested classes for each behavior.
  • Benefits
    • Smaller, more focused test classes
  • Liabilities
    • Potential code duplication
      • May consider duplicating code if it’s for the purpose of communication (but use this carefully)
    • Issues with test runners — not all can deal with nested classes
  • Related issues
    • Do you need SetUp and TearDown?

Lesson #5: Don’t use SetUp or TearDown

(I smell a holy war)

  • If the tests are not all orthogonal, you can end up with a test that doesn’t need anything from the SetUp method.
  • If SetUp takes a long time, you’d be paying the price for every test, even those that don’t need all of it.
  • If there are tests that don’t need all of SetUp, readability suffers.
  • It’s a hacking point. It’s a place where people can add code that you might or might not like.
  • When asked about the duplication, he suggested pulling the duplicated code into a method, and calling it at the beginning of each test. That wouldn’t necessarily be a totally bad idea, if SetUp was the only thing he was trying to get rid of.
  • Benefits
    • Readability (if it removes duplication)
    • Test isolation (but only if it means you get rid of all fixture state, and put absolutely all your state into local variables)
  • Liabilities
    • Duplicated initialization code
    • Things he didn’t mention, that I will (having run into all of them):
      • Duplicated cleanup code
      • Try..finally in every test to make sure your cleanup code gets run
      • Signal/noise ratio: if a test gets too long, it’s much harder to tell what it’s actually trying to accomplish
      • Poor test isolation: if you have any fields on your fixture class, you will forget to initialize some of them in some of the tests, which will introduce test-order dependencies (since NUnit shares the same fixture instance among all the tests in the suite)
  • Related issues
    • Small fixtures

Lesson #6: Don’t use abstract base test classes

He’s apparently specifically referring to the practice of putting tests on a base class, and inherit them in descendants. We use this technique, though sparingly; you do take a big hit in readability, so it really has to be worth having the same tests (including newly-written tests) apply in more than one place.

What’s wrong with base classes?

  • If the tests don’t all apply to all the derived classes, you’d have a problem. (Um, duh. You’d notice when they failed, wouldn’t you?)
  • Removes duplication at the expense of readability. (Fair point.)
  • He wants us to put the test logic into a utility function instead, and call that from the different descendants. (Trouble is, that doesn’t help make sure that all new tests get added to all the fixtures. You don’t use this pattern unless you want all the tests in all the descendants.)
  • Benefits
    • Readability
    • Test isolation
  • Related issues

Lesson #7: Improve testability with Inversion of Control

  • Martin Fowler article: Inversion of Control Containers and the Dependency Injection pattern
  • Dependency Injection
    • Constructor injection
    • Setter injection
  • Don’t want errors to cascade across all parts of the program.
  • Benefits
    • Better test isolation
    • Decoupled class implementation
  • Liabilities
    • Decreases encapsulation
    • Interface explosion
  • Related issues
    • Dependency injection frameworks are overkill for most applications

Side note: Mocks are good for interaction testing, bad for state testing.

TechEd 2008 notes: Understanding C# Lambda Expressions

Monday, June 9th, 2008

This was a lunch session, so pretty short. It turned out to be pretty introductory-level, just about grokking the syntax (which I pretty much already did).

Understanding C# Lambda Expressions
Scott Cate
myKB.com

Operators: most are very mnemonic, very self-explanatory. But what about =>?

Read => as “reads into” or “feeds into”.

BuildMatrix((a, b) => (a+b).ToString());

History of Delegates in .NET

  • Forget the compiler for a minute. What does the word “delegate” mean? “I don’t have time to (or don’t know how to) do this; I’m going to offload it to someone else and take the credit.”
  • You’ve mastered delegates if you could write a class with an event, and wire up that event, in Notepad, without Intellisense.
  • Define the delegate type. No implementation, just a signature.
  • .NET 1.0: Pass the method name as a parameter (or whatever). (Actually, in 1.0 I think maybe you had to do new DelegateType(MethodName).)
  • .NET 2.0: anonymous delegates. BuildMatrix(delegate(int a, int b) { return (a+b).ToString(); }
    • Return type is inferred.
  • .NET 3.0: BuildMatrix((a, b) => (a+b).ToString());
    • The stuff after => is an anonymous delegate. The stuff before it is the parameter list.
    • You can define the parameter types, or the compiler can infer them.
    • Can omit parentheses if there’s only one parameter.
  • Same thing without predefining the delegate type: void BuildMatrix(Func<int, int, string> operate)
  • Don’t need curly braces and don’t need return — can just put an expression. You can also put braces with statements (in which case you do need return).

Errata — details the presenter got mixed up:

  • Built a grid in HTML, and it looks like he got his X and Y loops reversed. Yes, this is nitpicky.
  • Told us you can make two delegates with the same name but different parameters (one with two ints and one with two decimals). You can’t; it won’t compile (I double-checked). They can have the same name if they have a different number of generic parameters (since the number of generic parameters is part of the name), but you can’t do it if they’re non-generic.
  • Told us the compiler generates a new delegate type behind the scenes when you pass an anonymous delegate (it doesn’t, it uses the actual delegate type that the function expects; I double-checked)

Joe White's Blog copyright © 2004-2011. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS). Privacy policy