After several years of following the bad practice handed down from \'architects\' at my place of work and thinking that there must be a better way, I\'ve recently been reading u
What you mention is called state testing. There's also behavior testing. The techniques used for that are Dependency Injection, Inversion Of Control, and Mocking:
All side effects of your class are implemented as method invocations on its "dependencies" -- i.e. objects supplied from the outside, usually in constructor. Then, in your unit-test, you supply a fake object instead of a real one. The fake object can remember if its' certain method was called, and that's what you assert in your test.
There exist number of Mocking Frameworks that automate mock object creation by dynamically generating classes that implement a given interface. Most popular are Rhino.Mocks and Moq.