Tag: Testing
Shipping Software – A response to Joel Spolsky
by bhartsock on Sep.28, 2009, under Uncategorized
Joel recently posted The Duct Tape Programmer which has received an enormous amount of buzz, both positive and negative. At work, I received emails telling me that the article is a must read, while receiving different emails flaming Joel. If you haven’t read it, I highly encourage you to do so. In short, it is about shipping software above all else.
I have spent the evening catching up on blogs, many of which are just responses to Joel’s, so I felt I should jump on the bandwagon. Instead of writing only my own sentiments, I have included a couple other thoughts from different bloggers to help clarify everything.
Uncle Bob really helped clarify the sentiments of developers.
Now don’t get me wrong. I’m the “Clean Code” guy. I want your code clean. I don’t want you making a mess. On the other hand, I want you to ship. I don’t want you gilding the lilly. I don’t want you wrapped up in endless polishing.
I want you to ship, but I don’t want you to ship shit.
If you think I’m contradicting myself, you’re wrong. There is no contradiction in the notion that you must ship, and that you must be proud of what you ship.
The programmer who spends weeks building the perfect structure does just as much harm to the project as the programmer who hacks a bunch of crap together. Neither have struck the balance that’s required.
In short, it’s bad to use too much duct tape. But I’d be suspicious if I didn’t see some duct tape!
While Casey Charlton explains the disconnect between the business and the developer.
Developers and business owners are not aligned in their goals – we prioritise the three factors [time, scope, quality] very differently, and for different reasons.
Only two things can happen here, your developers need to align with their business objectives, or the business needs to align with the developers – or they can both compromise.
Agile is all about the compromise, making both sides aware of the issues involved, and then coming to an agreement, but fundamentally – it is STILL A BUSINESS DECISION.
While it is the responsibility of a professional developer to explain all the problems they see with low quality code, and to make their boss aware of all the potential future issues this may cause, it is also their professional responsibility to go with the decision their boss makes.
As for what I think, it is pretty simple. Shipping software and shipping quality software should be synonymous. It boils down to having great developers capable of great things. Writing tests that speed the team up, not down. Developing architectures that make sense now, not in 30 years. And finally, capable of releasing great software by the deadline.
Using Extension Methods to clean up Mocks (MoQ)
by bhartsock on Sep.01, 2009, under Uncategorized
Mock’s can quickly become an ugly beast. They require lots of complex setup and verification. I have had good luck with using extension methods to simplify the complexity.
Assume we have the following code to implement our data layer on top of some ReST API.
public interface IWebClient { string DownloadString(string url); string UploadValues(string method, string address, NameValueCollection data); } public class WebClientWrapper : IWebClient { private WebClient client; public WebClientWrapper() { client = new WebClient(); } public string DownloadString(string url) { return client.DownloadString(url); } public string UploadValues(string method, string address, NameValueCollection data) { return Encoding.UTF8.GetString(client.UploadValues(address, method, data)); } }
In the business/domain layer, we have a class that uses IWebClient to get some information from the API.
public class BusinessObject { IWebClient client; public BusinessObject(IWebClient _client) { client = _client; } public XmlDocument FindCustomer(string search) { var result = client.DownloadString( string.Format("http://someApi/customers?search={0}", HttpUtility.UrlEncode(search)) ); return BuildXml(result); } public XmlDocument FindCustomer(char startsWith) { var result = client.DownloadString( string.Format("http://someApi/customers?startsWith={0}", HttpUtility.UrlEncode(startsWith.ToString())) ); return BuildXml(result); } private XmlDocument BuildXml(string result) { var doc = new XmlDocument(); doc.LoadXml(result); return doc; } }
How do we go about testing this? My first attempt would look something like the following, relying heavily on MoQ.
[TestFixture] public class BusinessObjectTests { string resultXml = "<xml><customer></customer></xml>"; Mock<IWebClient> client; BusinessObject bo; [SetUp] public void Setup() { client = new Mock<IWebClient>(MockBehavior.Strict); bo = new BusinessObject(client.Object); } [Test] public void Find_customer_using_search() { client.Setup(s => s.DownloadString("http://someApi/customers?search=searchVal")) .Returns(resultXml) .AtMostOnce(); bo.FindCustomer("searchVal"); client.VerifyAll(); } [Test] public void Find_customer_using_filter() { client.Setup(s => s.DownloadString("http://someApi/customers?startsWith=a")) .Returns(resultXml) .AtMostOnce(); bo.FindCustomer('a'); client.VerifyAll(); } }
But I don’t like this. It is very verbose, and doesn’t resuse functionality very well. Morever, in real world examples, there would probably be many more functions with very similar setup and verification steps. How can we refactor this to make it better?
public static class ClientMockExtensions { public static void VerifyGetContainedParmeter(this Mock<IWebClient> client, string name, string value) { client.Verify(c => c.DownloadString( It.Is<string>(s => s.IndexOf(name + "=" + value) > s.IndexOf("?")))); } } [TestFixture] public class BusinessObjectTests { string resultXml = "<xml><customer></customer></xml>"; Mock<IWebClient> client; BusinessObject bo; [SetUp] public void Setup() { client = new Mock<IWebClient>(MockBehavior.Strict); bo = new BusinessObject(client.Object); client.Setup(s => s.DownloadString( It.Is<string>(str => str.StartsWith("http://someApi/customers")))) .Returns(resultXml) .AtMostOnce(); } [Test] public void Find_customer_using_search() { bo.FindCustomer("searchVal"); client.VerifyGetContainedParmeter("search", "searchVal"); client.VerifyAll(); } [Test] public void Find_customer_using_filter() { bo.FindCustomer('a'); client.VerifyGetContainedParmeter("startsWith", "a"); client.VerifyAll(); }
In the example, I use extension methods to reuse verification steps, which also makes the tests much cleaner. Too many times developers stay away from complex verification steps in favor of complex setups. I think it is cleaner to do a more generic setup, and then use verify to get down to the specifics of what was done.
Using Pipeline.Input for Powershell testing
by bhartsock on Mar.30, 2009, under Uncategorized
Last week, I posted about how to unit test powershell, which I have been working with a little bit over the weekend. One thing I quickly realized was testing interaction with the pipeline is a must for Powershell. It’s pretty easy to do.
Let’s start with the Get-Service cmdlet that ships with Powershell. If you load up reflector, you will see the follow class definition.
[Cmdlet("Get", "Service", DefaultParameterSetName="Default")] public sealed class GetServiceCommand : MultipleServiceCommandBase { // Methods public GetServiceCommand(); protected override void ProcessRecord(); // Properties [Parameter(Position=0, ParameterSetName="Default", ValueFromPipelineByPropertyName=true, ValueFromPipeline=true), Alias(new string[] { "ServiceName" })] public string[] Name { get; set; } }
Remembering the base test fixture from the previous post on TDD in Powershell, I can quickly write up a few tests that test a few different use cases of the get-service cmdlet with
[Test] public void Get_Service_with_single_string_in_pipeline() { // "MySQL" | get-service var name = "MySQL"; var pipeline = Runspace.CreatePipeline(); pipeline.Input.Write(name); pipeline.Commands.Add("get-service"); var result = pipeline.Invoke(); AssertThatPipelineResultIsService(result, name); } [Test] public void Get_Service_with_single_object_in_pipeline_using_Name_property() { //New-Object PSObject | Add-Member NoteProperty Name "MySQL" -PassThru | get-service var name = "MySQL"; var pipeline = Runspace.CreatePipeline(); pipeline.Input.Write(new { Name = name }); pipeline.Commands.Add("get-service"); var result = pipeline.Invoke(); AssertThatPipelineResultIsService(result, name); } [Test] public void Get_Service_with_single_object_in_pipeline_using_ServiceName_property() { //New-Object PSObject | Add-Member NoteProperty ServiceName "MySQL" -PassThru | get-service var name = "MySQL"; var pipeline = Runspace.CreatePipeline(); pipeline.Input.Write(new { ServiceName = name }); pipeline.Commands.Add("get-service"); var result = pipeline.Invoke(); AssertThatPipelineResultIsService(result, name); } private void AssertThatPipelineResultIsService(Collection<PSObject> result, string name) { Assert.That(result.Count == 1); Assert.That(result[0].BaseObject is ServiceController); Assert.That((result[0].BaseObject as ServiceController).ServiceName == name); }
By using pipeline.Input.Write(), I can write to the pipeline before invoking commands. Really easy to do, and super useful, because each Powershell cmdlet can probably be called a bunch of different ways.
Where can you use it? Snap in development or testing your own Powershell scripts. Stop guessing how the pipeline is going to work and test it.
TDD with Powershell, from the client perspective
by bhartsock on Mar.27, 2009, under Uncategorized
Is it possible? Yes, and it is actually relatively easy. The hardest part can be figuring out how to mock/stub out certain functionality so your testing small units as opposed to full acceptance testing. The line can get blurry, but I don’t really care. Testing is half the battle.
But to be clear, the focus of my testing is to test how a snap-in is working. It sounds like an integration test, and maybe it is, but there is no reason you couldn’t test any powershell script using some of the steps outlined here. Just be flexible and creative.
Start by creating a nice base test fixture.
public abstract class PowershellTestFixture { protected Runspace Runspace { get; set; } public void CreateRunspace() { Runspace = RunspaceFactory.CreateRunspace(CreateConfiguration()); Runspace.Open(); } public void CloseRunspace() { Runspace.Close(); Runspace.Dispose(); } private RunspaceConfiguration CreateConfiguration() { var config = RunspaceConfiguration.Create(); PSSnapInException warning; config.AddPSSnapIn("SomeCustomSnapIn", out warning); return config; } protected Collection<PSObject> ExecutePowershell(string script) { return Runspace.CreatePipeline(script).Invoke(); } }
In this base class, I just created some nice helper methods, and one method that samples how to add a snap-in to the runspace.
Now, just write a test, and add your assertions. And it will work!
[TestFixture] public class TestSomethingStupid : PowershellTestFixture { [SetUp] public void Setup() { CreateRunspace(); } [TearDown] public void TearDown() { CloseRunspace(); } [Test] public void GetServiceWhereNameIsMySql() { string cmd = @" get-service | where { $_.name -eq 'MySQL' } "; var result = ExecutePowershell(cmd) .Select(o => o.BaseObject) .Cast<System.ServiceProcess.ServiceController>() .First(); Assert.AreEqual(result.ServiceName, "MySQL"); } }
Obviously this test is stupid. But that’s not the point. In a very few lines, I have tested the output of some powershell. Pretty cool if you ask me, especially if your coding a snap in. If you aren’t automating the tests, how else can you verify it works except to recompile, install, open powershell, and type some code? Very slow and painful!
It is important to note, there are other ways to test snap-in’s. What I really wanted to see is how my cmdlet’s looked from the powershell perspective, not the C# perspective.
Database integration testing, Interested?
by bhartsock on Feb.18, 2009, under Uncategorized
Testing database queries is super important, but not easy enough. It can be done, but usually you have to write custom test fixtures and spend too much time doing it. Every project needs to test database integration, so why isn’t there a library out there to make it easier? NDbUnit seems somewhat dead, and only works on a specific set of database providers. Even worse, it relies on a ton of XML setup, which I hate.
So I decided to play around with creating an NUnit addin that makes this a lot easier. Does the following code interest anyone?
[MySqlDbTestFixture("Data Source=localhost;User ID=root;"), RandomDatabaseName, ImportFromFile("schema.sql")] public class SomeTestFixture { [DbTest, ImportFromFile("BadCompanyDataInDb.sql")] public void SomethingWorksWithBadCompanyData(IDbConnection conn) { ... } }
I have most of it working, and want to see if there are any developers that might think of using it. Am I on the right track? Any thoughts or ideas for improvement?
(I told you I would have some code in a post this week)