Thursday, May 17, 2007

Object Oriented vs Test Oriented

Roy is debating this very topic - that is - for any API that needs to be unit-tested, do we forego OOD principles, such as hiding irrelevant stuff, in favour of testability? 

To summarise Roy's case:  he's using public bits of the FxCop API to automate (unit-test) his custom rules - but... the FxCop team have realised they've got a bunch of types that shouldn't be exposed and will be making them internal in the next 'Orcas' release.  This means that Roy's unit-tests will not compile against the new API.

I think the issue here is Roy using something in the API that wasn't intended to be exposed but is rather useful; that is, offering an API to automate custom rules. From what I can see, the FxCop team are quite correctly 'concealing' types that shouldn't be exposed; I for one would be glad of this decision if I were looking through their API 'contracts' - I wouldn't want to spend time creating and trying to use an exposed type if it weren't mean to be exposed.

I do see the need to automate testing of custom rules, but I think this should be designed as appopriate additions to the API for that particular purpose (rather than relying on accidentally exposed types spread throughout the API to acheive the same thing).  This way, the API stays tight, and also enables a more succinct, targeted API for automating tests for custom rules.

Of course, this doesn't anwser the more general question "How do I design an API that hides irrelevant stuff but also enables the irrelevant stuff to be tested?"

In fact, in the paragraph above, I was going to use the term 'How do I design an API that is both OO and easily tested', but, as Framework Design Guidelines correctly states, API's are not meant to be Object Oriented (the implementation is OO, not the public API).

So, I suppose the question really becomes 'How do I hide my OO implementation but make it easily testable?"

One way is to have the unit tests in with the implementation. I'd prefer not to do this, but I've done it in the past. I've also taken the other route and made the odd type here and there public instead of internal so I can test externally.

I've been toying with the idea of having a 'Unit Test Facade' object in my OO code/API. Anyone use the 'API' can see my intent from what's exposed, and anyone running unit tests can exercise the implementation via the facade. Of course, this adds overhead, but does make the distinction between the API and implementation.

Wednesday, May 09, 2007

Uploading to an FTP server with parameters

This post will have a limited audience (even more limited than my normal posts!), but if you're searching for a solution to this particular problem, I hope you'll be glad you found this.

I was recently tasked with uploading a file to an FTP server. I optimistically estimated that it shouldn't take long as we're using .NET 2.0 and there's FTP stuff in 2.0.

But, the particular server I had to write to took parameters on the PUT command (something I'd never seen before). The put looked something like this:
PUT thefile.txt %destinationFilename.txt%param2%%param4

The parameters tell the server things like what 'mailbox' to use, what account to use to write the file, etc. etc.

A quick bit of info on FTP:  you first send the PUT request, and get a response, followed by other requests (for things like credentials), followed ultimately by sending a STOR command.

The .NET 2.0 implementation of FtpWebRequest does not take into account differences between the 'request (PUT)' parameters and the 'command (STOR) parameters'.

To get around this, one must use sockets directly.  I found a Microsoft KB article that contained just that.  The sample demonstrated using pluggable protocol handlers.  I removed the bits that weren't relevant and modified it to handle command parameters.

I fronted all this with an FtpTransfer class that deals with just uploading files. Typical usage looks like this:

FtpTransfer ftpTransfer = new FtpTransfer( new Uri( @"ftp://serverRequiringParameters" ), @"yourUsername", @"yourPassword" ); ftpTransfer.UploadFileWithParameters( @"c:\temp\ftptest.txt", @"destinationFilename.txt", @"%destinationFilename.txt%PARAM2%PARAM3" );

The source (and a Visual Studio 2005 project) can be download here.