Being Cellfish

Stuff I wished I've found in some blog (and sometimes did)

December, 2008

Change of Address
This blog has moved to blog.cellfish.se.
Posts
  • Being Cellfish

    The 2008 Advent Calendar wrap up

    • 3 Comments

    Writing all these tests I sometimes felt that the changes between two days was not significant. And sometimes I felt there were versions that did not make it into this advent calendar. But I stuck with the versions you have seen since I think they represent a quite natural evolution of the initial test and hence I have not presented any side tracks that eventually turn into a dead end because I wanted to progress toward the final version which is the one I like most of all these versions. Also I had to be a little bit puristic and let even the smallest changes result in a version by it self rather than merging a number of small changes into a single version change in order get 24 different versions. There are however a few of the versions that I think are worth a special mentioning.

    • December 3rd: I think this is a typical example of how people write their tests when they're starting out to use TDD. In my experience TDD novices tend to put too much into each test.
    • December 5th: The second most common mistake is to forget that standard software engineering practices and common sense still apply to the test code. They tend to forget code reuse in their tests.
    • December 11th: I think this is the first acceptable version in this series. Simple, easy to understand tests with code reuse. TDD novices that take TDD seriously typically end up with this kind of tests pretty soon.
    • December 15th: The use of an object that extends the object under test and adds functionality needed to simplify testing is a great step forward toward writing good tests (IMHO). I think this version of the test basically is the first peek at BDD-type test-writing.
    • December 20th: Now we have easy to understand tests and each method have really descriptive names that are easy to read. I think this is the first really good version of the test in this series.
    • December 24th: In my experience people tend to put many different kinds of tests into the same test class ending up with tear-down code that has to take take the state of several tests into account. This makes the test class more complex than it has to be. The use of several specialized test classes for different types of test scenarios is definitely something you start thinking of after writing several unit tests. I think it is a common misconception that you should have one test class for each production class. Some test classes will test several production classes while others production classes will need several test classes to complete the test suite.

    Please leave a comment and let me know what your favorite version in this series of test is!

  • Being Cellfish

    2008 Advent Calendar December 12th

    • 2 Comments
    
    
    1: public class Advent12 : IDisposable 2: { 3: private IFileUtil m_file; 4:   5: private void SetUp(string content) 6: { 7: m_file = new FileUtil("SomeFile.txt"); 8: m_file.Create(content); 9: } 10:   11: public void Dispose() 12: { 13: m_file.Delete(); 14: } 15:   16: [Fact] 17: public void TestReadReadableFile() 18: { 19: SetUp("CONTENT"); 20: string content = m_file.Read(); 21: Assert.Equal<string>("CONTENT", content); 22: } 23:   24: [Fact] 25: public void TestReadUnreadableFile() 26: { 27: SetUp("SHOULD NOT BE ABLE TO READ THIS"); 28: m_file.Readable = false; 29: Assert.Throws<AccessViolationException>(() => { m_file.Read(); }); 30: } 31: }

    Since the setup-method is called explicitly, why not have several setup-methods for different kinds of setup?

  • Being Cellfish

    2008 Advent Calendar December 5th

    • 2 Comments
    
    
    1: public class Advent5 : IDisposable 2: { 3: private IFileUtil m_file; 4:   5: public void Dispose() 6: { 7: m_file.Delete(); 8: } 9:   10: [Fact] 11: public void TestReadOK() 12: { 13: // Create a test file 14: m_file = new FileUtil("SomeFile.txt"); 15: m_file.Create("CONTENT"); 16:   17: // Should be able to read file 18: Assert.DoesNotThrow(() => { m_file.Read(); }); 19: } 20:   21: [Fact] 22: public void TestReadFails() 23: { 24: // Create a test file 25: m_file = new FileUtil("SomeFile.txt"); 26: m_file.Create("CONTENT"); 27:   28: m_file.Readable = false; 29:   30: // Should NOT be able to read file. 31: Assert.Throws<AccessViolationException>(() => { m_file.Read(); }); 32: } 33: }

    Now we're using Xunit-net's clean up mechanism, the IDisposableinterface. We still got some redundant code in the setup part of each test. Next I'll refactor that.

  • Being Cellfish

    2008 Advent Calendar December 17th

    • 2 Comments
    
    
    1: public class Advent17 2: { 3: private FileUtilWithDelete SetUp(string content, bool readable) 4: { 5: FileUtilWithDelete file = new FileUtilWithDelete("SomeFile.txt"); 6: file.Create(content); 7: file.Readable = readable; 8: return file; 9: } 10:   11: [Fact] 12: public void TestReadReadableFileReturnsFileContent() 13: { 14: using (FileUtilWithDelete file = SetUp("CONTENT", true)) 15: { 16: string content = file.Read(); 17: Assert.Equal<string>("CONTENT", content); 18: } 19: } 20:   21: [Fact] 22: public void TestReadUnreadableFileThrowsCorrectException() 23: { 24: using (FileUtilWithDelete file = SetUp("SHOULD NOT BE ABLE TO READ THIS", false)) 25: { 26: Assert.Throws<AccessViolationException>(() => { file.Read(); }); 27: } 28: } 29: }

    Starting all test methods with "Test" does not really add any value to the name either. Naming the tests something that sounds like a real sentence is something I prefer.

  • Being Cellfish

    2008 Advent Calendar December 18th

    • 1 Comments
    
    
    1: public class Advent18 2: { 3: private FileUtilWithDelete SetUp(string content, bool readable) 4: { 5: FileUtilWithDelete file = new FileUtilWithDelete("SomeFile.txt"); 6: file.Create(content); 7: file.Readable = readable; 8: return file; 9: } 10:   11: [Fact] 12: public void ReadingAReadableFileReturnsFileContent() 13: { 14: using (FileUtilWithDelete file = SetUp("CONTENT", true)) 15: { 16: string content = file.Read(); 17: Assert.Equal<string>("CONTENT", content); 18: } 19: } 20:   21: [Fact] 22: public void ReadingAnUnreadableFileThrowsCorrectException() 23: { 24: using (FileUtilWithDelete file = SetUp("SHOULD NOT BE ABLE TO READ THIS", false)) 25: { 26: Assert.Throws<AccessViolationException>(() => { file.Read(); }); 27: } 28: } 29: }

    Now I like the names but they are hard to read. Why not add some space?

  • Being Cellfish

    2008 Advent Calendar December 1st

    • 1 Comments
    
    
    1: public class Advent1 2: { 3: [Fact] 4: public void TestRead() 5: { 6: // Create a test file 7: IFileUtil file = new FileUtil("SomeFile.txt"); 8: file.Create("CONTENT"); 9:   10: // Should be able to read file 11: try 12: { 13: file.Read(); 14: } 15: catch (Exception) 16: { 17: throw new AssertException("Unexpected exception thrown"); 18: } 19:   20: file.Readable = false; 21:   22: // Should NOT be able to read file. 23: try 24: { 25: file.Read(); 26: throw new AssertException("No exception thrown"); 27: } 28: catch (AccessViolationException) 29: { 30: } 31:   32: // Clean up 33: file.Delete(); 34: } 35: }

    With this first version of the test there I have not utilized all the features of Xunit.net. I basically do all the verification my self and create test failures by explicitly throwing AssertFailure exceptions. There are several problems with this code but the only problem that will be addressed in the next version of this test is if line 25 throws another exception than AccessViolationException. Xunit.net will save the day but it is quite ugly So in tomorrows version we'll fix that.

  • Being Cellfish

    2008 Advent Calendar December 2nd

    • 0 Comments
    
    
    1: public class Advent2 2: { 3: [Fact] 4: public void TestRead() 5: { 6: // Create a test file 7: IFileUtil file = new FileUtil("SomeFile.txt"); 8: file.Create("CONTENT"); 9:   10: // Should be able to read file 11: try 12: { 13: file.Read(); 14: } 15: catch (Exception) 16: { 17: throw new AssertException("Unexpected exception thrown"); 18: } 19:   20: file.Readable = false; 21:   22: // Should NOT be able to read file. 23: try 24: { 25: file.Read(); 26: throw new AssertException("No exception thrown"); 27: } 28: catch (AccessViolationException) 29: { 30: } 31: catch (Exception) 32: { 33: throw new AssertException("Unexpected exception thrown"); 34: } 35:   36: // Clean up 37: file.Delete(); 38: } 39: }

    Now I've added a handler for unexpected exceptions but this is still a pretty cumbersome way to write tests verifying that exceptions are thrown or not correctly. Especially since Xunit.net provides us with a really simple way to handle this for us. That is what will happen next.

  • Being Cellfish

    2008 Advent Calendar December 3rd

    • 0 Comments
    
    
    1: public class Advent3 2: { 3: [Fact] 4: public void TestRead() 5: { 6: // Create a test file 7: IFileUtil file = new FileUtil("SomeFile.txt"); 8: file.Create("CONTENT"); 9:   10: // Should be able to read file 11: Assert.DoesNotThrow(() => { file.Read(); }); 12:   13: file.Readable = false; 14:   15: // Should NOT be able to read file. 16: Assert.Throws<AccessViolationException>(() => { file.Read(); }); 17:   18: // Clean up 19: file.Delete(); 20: } 21: }

    Using XUnit.net asserts to verify exceptions is much better than what we did yesterday. Now the test starts to be small enough to be understood easily. But I think there is a major problem with this test. We're not only testing that we cannot read an unreadable file, I'm also verifying that I can read a readable file. I think this should be split up into two different tests and that is what will happen next.

  • Being Cellfish

    2008 Advent Calendar December 4th

    • 0 Comments
    
    
    1: public class Advent4 2: { 3: [Fact] 4: public void TestReadOK() 5: { 6: // Create a test file 7: IFileUtil file = new FileUtil("SomeFile.txt"); 8: file.Create("CONTENT"); 9:   10: // Should be able to read file 11: Assert.DoesNotThrow(() => { file.Read(); }); 12:   13: // Clean up 14: file.Delete(); 15: } 16:   17: [Fact] 18: public void TestReadFails() 19: { 20: // Create a test file 21: IFileUtil file = new FileUtil("SomeFile.txt"); 22: file.Create("CONTENT"); 23:   24: file.Readable = false; 25:   26: // Should NOT be able to read file. 27: Assert.Throws<AccessViolationException>(() => { file.Read(); }); 28:   29: // Clean up 30: file.Delete(); 31: } 32: }

    Now that the initial test has been split up into two tests. One testing reading a readable file and one testing an unreadable file. Now I got some redundant code I wanna get rid of. The first thing is the clean up code. It is not run if the test fails and that is probably a bad thing. So next I'll fix that.

  • Being Cellfish

    2008 Advent Calendar December 6th

    • 0 Comments
    
    
    1: public class Advent6: IDisposable 2: { 3: private IFileUtil m_file; 4:   5: public Advent6() 6: { 7: m_file = new FileUtil("SomeFile.txt"); 8: m_file.Create("CONTENT"); 9: } 10:   11: public void Dispose() 12: { 13: m_file.Delete(); 14: } 15:   16: [Fact] 17: public void TestReadOK() 18: { 19: Assert.DoesNotThrow(() => { m_file.Read(); }); 20: } 21:   22: [Fact] 23: public void TestReadFails() 24: { 25: m_file.Readable = false; 26: Assert.Throws<AccessViolationException>(() => { m_file.Read(); }); 27: } 28: }

    With some redundant code broken out into the common setup method (the default constructor if you're not familiar with Xunit.net) there is another thing that bothers me about the TestReadOK-test. We're not actually verifying the content of the file. Let's fix that in the next version of this test.

Page 1 of 3 (25 items) 123