Ben Biddington

Whatever it is, it's not about "coding"

RSpec — common base specs

leave a comment »

Sometimes I am fond of creating inheritance chains for tests, which is easy in Java or C# say, but not quite as obvious in rspec.

Define and register a base class

It just needs to inherit from Spec::Example::ExampleGroup so it’s runnable.

require 'spec/example/example_group'
class UnitTest < Spec::Example::ExampleGroup
   protected
   def you_can_call_this
   end
end

Spec::Example::ExampleGroupFactory.register(:unit_test, UnitTest)

Set the type when describing

describe 'By supplying the :type', :type => :unit_test do
    it 'this example group inherits from whatever class you supply as :type' do
        self.protected_methods.should include('you_can_call_this')
    end
end

You now have common base class to your specifications.

Written by benbiddington

6 November, 2010 at 13:37

Posted in development

Tagged with , ,

Test driving and test coverage

leave a comment »

Yesterday I enabled rcov on my current project and was surprised that it had 100 per cent unit test coverage.

But perhaps I should not have been surprised. After all, if you are truly test driving, how could you possibly leave anything uncovered?

Written by benbiddington

7 October, 2010 at 13:37

Posted in development

Tagged with ,

Refactoring Example — Fat Controllers

with 2 comments

We have an MVC controller that takes some input from a user, finds a file in a particular MP3 flavour, and then calculates the hash of the MP3 frames in that file.

Here’s what it looked like to begin with (an arrow means depends on):

Mp3HashController
|---------------> TrackFileFinder
|---------------> StreamHasher
|---------------> Log

Operation:

  • Take input of trackid and format id (both numbers)
  • Open a stream on the file
  • Supply that stream to the StreamHasher
  • Return the hash as text to user

Next requirement — learning file hashes

This works as required but we can improve performance by reducing the number of times we calculate a file’s hash. Assuming each file is static — i.e., its MP3 frames will never change — then we only need to calculate its hash once.

Rather than do this every time, we could save the result somewhere — a database perhaps. Which means we are introducing new behaviour.

When producing a hash, first check whether it already exists
If it does exist, then return it
Otherwise generate it and store it for next time

We could naively add a new HashRepository collaborator:

Mp3HashController
|---------------> TrackFileFinder
|---------------> StreamHasher
|---------------> Log
|---------------> HashRepository

But now our interface is expanding, this has a habit of getting out of control and you can end up with ten constructor arguments. This is commonly known as the “Too Many Dicks on the Dance Floor” problem.

So what’s wrong with it?

  • Mp3HashController is no longer composing its behaviour from one layer of abstraction. This notion of learning return values has changed that. It is now exposed to details it shouldn’t have any knowledge of let alone dependency on.
  • Mp3HashController is now more difficult to test, there are more paths that have to exercised though the same interface
  • There is new conditional behaviour here that clearly belongs on its own — clients should not even know this is happening
  • It is much easier to test the learning behaviour on its own — I shouldn’t have to probe a controller
  • I shouldn’t have to describe an object’s behaviour in terms of another objects interface, I should be able to use that object directly
  • I would likely have to suppress some behaviour(s) while testing others. This will be manifest itself as complicated stubbing
  • Lots of dependent stubbing. Each of those collaborators are actually collaborators themselves. I think this is a smell. I shouldn’t have to consider this when unit testing Mp3HashController.

There is an opportunity to introduce an abstraction here. If we consider that all Mp3HashController requires is something to get a hash, then we can actually reduce it to:

Mp3HashController
|---------------> Log
|---------------> HashRepository

And then we have a HashRepository implementation like this:

LearningHashRepository
|---------------> TrackFileFinder
|---------------> StreamHasher
|---------------> HashRepository

The LearninghHashRepository has the responsibility of storing any hashes that don’t exist.

This could probably be condensed even further. TrackFileFinder and StreamHasher represent the concept of obtaining the hash of a file given a track identifier, so they can be combined. This reduces LearningHashRepository to a sort of write-through cache.

Written by benbiddington

9 August, 2010 at 13:37

Posted in development, oop

Tagged with , ,

SSH, cygwin and domain users

leave a comment »

Yes you can log in to your local computer via ssh with a domain account.

If it seems you can’t (i.e., your password is rejected) then you  most likely need to export your user accounts and groups so cygwin can see them.

Another clue that you need to export is if you get a message like:

Your group is currently "mkpasswd".  This indicates that
the /etc/passwd (and possibly /etc/group) files should be rebuilt.
See the man pages for mkpasswd and mkgroup then, for example, run
mkpasswd -l [-d] > /etc/passwd
mkgroup  -l [-d] > /etc/group
Note that the -d switch is necessary for domain users.

To export domain users:

$ mkpasswd -d >> /etc/passwd

To export groups:

$ mkgroup > /etc/group

Troubleshooting

Errors logging in as domain user

2 [main] -bash 31884 C:\cygwin\bin\bash.exe: *** fatal error - couldn't dynamically determine load address for 'WSAGetLastError' (handle 0xFFFFFFFF), Win32 error 126
Connection to localhost closed.

This is because the cygwin sshd service must also run as domain account. I solved this by changing the user to my domain account.

Written by benbiddington

4 August, 2010 at 13:37

Why can’t I hang an extension method on a type?

leave a comment »

My brother asked me this. And while I don’t know, I did discover some interesting things along the way.

An extension method is nothing more than a compiler trick. It is simply a static method that takes an instance of the type being extended as an argument. That’s it.

The sugar part is that to you as a programmer, it appears to read more naturally in some cases.

They do not have any special privileges on private or protected members and they are not analagous to ruby module mixins (because the extended class cannot invoked extension methods).

[TBD: It is interesting that instance methods are supplied "this" as their first argument, see CIL]

[TBD: It is interesting that the compiler emits a callvirt instruction even in cases where call seems more appropriate just because callvirt has a null reference check. See: Why does C# always use callvirt?]

[TBD: Extensions are really a higher level abstraction because they operate only against public interface. An extension method is a client of the object it "extends"]

Example

namespace Examples {
    public class ExampleClass { }

    public static class Extensions {
        public static void ExtensionMethod(this ExampleClass instance) {
            instance.ToString();
        }
    }

    public class ThatUsesExampleClass {
        public void RunExample() {
            new ExampleClass().ExtensionMethod();
        }
    }
}

The interesting part is RunExample (because it invokes the extension method):

public void RunExample() {
    new ExampleClass().ExtensionMethod();
}

which compiles to:

.method public hidebysig instance void
RunExample() cil managed
{
    // Code size       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  newobj     instance void Examples.ExampleClass::.ctor()
    IL_0006:  call       void Examples.Extensions::ExtensionMethod(class Examples.ExampleClass)
    IL_000b:  nop
    IL_000c:  ret
} // end of method ThatUsesExampleClass::RunExample

It is clear that the compiler has done nothing more than redirect to a static method on a static class:

IL_0006:  call       void Examples.Extensions::ExtensionMethod(class Examples.ExampleClass)

Usage

The usual static method usage rules apply:

[Clean code chapter 6]
Procedural code (code using data structures) makes it easy to add new functions withoutchanging the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.

The complement is also true:
Procedural code makes it hard to add new data structures because all the functions must
change. OO code makes it hard to add new functions because all the classes must change.
So, the things that are hard for OO are easy for procedures, and the things that are
hard for procedures are easy for OO!

In any complex system there are going to be times when we want to add new data
types rather than new functions. For these cases objects and OO are most appropriate. On
the other hand, there will also be times when we’ll want to add new functions as opposed
to data types. In that case procedural code and data structures will be more appropriate.

Mature programmers know that the idea that everything is an object is a myth. Sometimes
you really do want simple data structures with procedures operating on them.

[TBD: Usage -- how does it fit with OO design?]

Back to the question

Still no answer.

But I can’t see any reason why the C# compiler couldn’t do the same for static constructs, but I wonder how you would express that on the extension method itself.  Perhaps that’s where the ExtensionAttribute comes in. Note: It currently is illegal to use the ExtensionAttribute directly.

But if you examine the IL for an extension method itself, you’ll see it has been applied:

.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() =
    ( 01 00 00 00 )
.method public hidebysig static void
    ExtensionMethod(class Examples.ExampleClass 'instance') cil managed {

    .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() =
        ( 01 00 00 00 ) 

    // Code size       9 (0x9)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0007:  pop
    IL_0008:  ret
} // end of method Extensions::ExtensionMethod

Written by benbiddington

4 August, 2010 at 09:15

Posted in development

Tagged with , , , , ,

FTP command line fu

with one comment

The Windows FTP utility can be easily automated, but if you want to record the output from a session it appears you need to do things in a particular way.

Redirection

It appears this does not work as expected, i.e. you can’t redirect stdout from an interactive ftp session to local file. It creates the file but with nothing in it.

Solution is to run ftp with the -s option which specifies a file containing the full list of commands to be run (including log-in).

> ftp -s:commands.txt > out/result.txt

Where your commands list looks like this example that prints the contents of a directory called phils_lunchbox :

open host_or_ip_address port
username
Password
cd phils_lunchbox
ls -l
quit
Done.

Tips

  • Don’t forget to add the quit or bye command at the end otherwise your command line’ll hang

References

Written by benbiddington

3 August, 2010 at 13:37

Posted in development

Tagged with , , ,

Outside-in development taken too far

with 2 comments

You may feel someone is taking things too far when you receive a set of scenarios like this:

Scenario 1: Warm Teapot

Given a Kettle of Boiling Water
When Boiling Water is poured in to the Teapot
Then it should* warm the Teapot

Scenario 2: Brewing the tea

Given a Kettle of Boiling Water
And 5 Teabags
When 5 Teabags are placed in the Teapot
And Boiling Water is poured in to the Teapot
And the Teapot is left with the above ingredients in it for 5 minutes
Then you should have Brewed Tea

Scenario 3: Pouring the tea

Given a Teapot of Brewed Tea
And a Mug with some Milk in it**
When the Brewed Tea is poured in to the Mug
Then you should have a Perfect Cup of Tea

* “Do or do not. There is no should”
** Debatable. I think we need to triangulate this, or consult the client.

Written by benbiddington

3 August, 2010 at 13:37

Posted in development

Tagged with , , ,

Follow

Get every new post delivered to your Inbox.