Test Driven Development by Example By Kent Beck

image

 

I spent some time working though TDD using C# over the last week. I thought the book was well-organized. Each chapter has small-enough chunks of logic broken down and demonstrating his points was great. Also, his wrap up at the end of the book had some really good pointers. I actually wrote his samples in C# twice. The 1st time I organized and coded my tests more along the lines of The Art of Unit Testing. However, many of his examples depend on multiple asserts in the same unit test and his naming and organization was so tightly coupled to the solution that I went through a second time and followed his testing code exactly (except for the differences between Java and C#). It made his story easier to follow – though I would not use his test naming and organization in a real project.

Some of his pointers I thought were useful:

  • Having the glass of water by your workstation to force you to take breaks (and it’s healthy too).
  • TDD is not TFD – though that is how Kent coded up his solutions. I am still in the camp that you create interfaces and stub out your classes using the built-in tools of VS2010 and then write your tests. You get all of the intelli-sense goodness with red-green-refactor paradigm intact.
  • I like Kent’s pragmatic approach to testing – tests are mutable and expendable. If they no longer have a use – get rid of them. Also, his iterative approach to development was spot on.
  • The advice about cheap desk and nice chair was made sense. It is amazing how those little things can add up to large productive gains.
  • “Failure is progress. Now we have a concrete measure of failure”
  • I follow Kent’s “Fake It” strategy for testing more often than not. I get the red, throw in anything to get green, and then slowly refactor to a better green.
  • Finally, TDD is the exact opposite of architectural-driven development (the mythical man month). You need to drive development with specification, tests, or hope. Everything you write code, you are using one of those three. You might as well be explicit in your choice…. Also, he mentions that TDD assumes that if you write better code, the more likely your project will be successful. That is often a faulty assumption…

Test Cleanup Errors

I spent some time refactoring some unit tests in a VS2010 project.  One of the changes I made was to move some variables to class-level and initialize them in the class startup in a couple integration tests.

 

[ClassInitialize()] public static void MyClassInitialize(TestContext testContext) { CreateTestObjects(); } private static void CreateTestObjects() { SwimGroup swimGroup = SwimGroupFactory.GetSwimGroup(testSwimGroupId); Practice practice = PracticeFactory.CreatePractice(DateTime.Parse(testCarpoolStartDate), false, DateTime.Parse(testCarpoolStartTime), DateTime.Parse(testCarpoolEndTime), swimGroup); PracticeFactory.InsertPractice(practice); testPracticeId = practice.Id; Driver driver = DriverFactory.GetDriver(testDriverId); Swimmer swimmer = SwimmerFactory.GetSwimmer(testSwimmerId); Carpool carpool = CarpoolFactory.CreateCarpool(practice, driver); carpool.Swimmers.Add(swimmer); CarpoolFactory.InsertCarpool(carpool); testCarpoolId = carpool.Id; }

 

Note that this is a regression test – I actually want to test the database connection – so I am not using a fake.

I also run a clean-up method to remove the test data that I injected into the dev database.

private static void DestroyTestObjects() { Carpool carpool = CarpoolFactory.GetCarpool(testCarpoolId); CarpoolFactory.DeleteCarpool(carpool); Practice practice = PracticeFactory.GetPractice(testPracticeId); PracticeFactory.DeletePractice(practice); }

 

I noticed two important things:

1) The Cleanup runs even if there is an error thrown in a test

 

image

 

2) If the Cleanup throws an exception, all of the tests still pass.

 

So the tests run in separate thread than the test controller.  Very cool – but makes me realize that unit testing multi-threaded apps must be a bear…

TDD using Interfaces

One of the tenants of TDD is that the tests are written, well, first.  The biggest problem I have with writing the tests first is one of developer productivity.  Call me a slave to tooling, but I really use intellisense when I code, so much to the point that I don’t even realize that I am using it.  With TDD, I can’t use Intellisense because the object has not been written yet.  As a way out of this problem, I thought of using interfaces.  I write the interface, write the test, then write the class under test.  I thought I would put my theory to the test with a basic example.  I created an interface like so:

1 using System; 2  using System.Collections.Generic; 3  using System.Linq; 4  using System.Text; 5  using Com.Tff.Patent.Data; 6 7  namespace Com.Tff.Patent.Domain 8 { 9 public interface IDoctrineFactory 10 { 11 static Doctrine GetDoctrine(int doctrineId); 12 static List<Doctrine> GetDoctrines(); 13 static List<Doctrine> GetDoctrines(int issueId); 14 } 15 } 16  

I then created a test like so:

1 [TestMethod] 2 public void GetDoctineReturnsCorrectValue() 3 { 4 IDoctrineFactory.GetDoctrine(1); 5 string expected = "aaa"; 6 string actual = doctrine.DoctrineName; 7 Assert.AreEqual(expected, actual); 8 9 } 10

However, I got a compiler error:

1 Error 1 The modifier 'static' is not valid for this item 2 3 Error 2 The modifier 'static' is not valid for this item 4 5 Error 3 The modifier 'static' is not valid for this item 6 7

That’s right – interfaces can’t be marked as static.  So then I thought of newing up a class in my test:

1 IDoctrineFactory doctrineFactory = new IDoctrineFactory(); 2 doctrineFactory.GetDoctrine(1); 3

The fact that I didn’t get intellisense was my first clue. The compiler error was my second:

1 Error 3 Cannot create an instance of the abstract class or interface

So then I created a concrete class using the refactoring tools in VS2010:

1 public class DoctrineFactory: IDoctrineFactory 2 { 3 public Data.Doctrine GetDoctrine(int doctrineId) 4 { 5 throw new NotImplementedException(); 6 } 7

This is better – I will get red b/c I have not implemented my methods yet – and I get intellisense in my unit tests. So for me, TDD is:

  • Write interface
  • Implement interfaces via VS2010
  • Write tests to get red
  • Write code logic to get to green

That way I get the intent behind TDD with modern tooling support.

Carpool Project: Part #4

I wrote this factory code:

1 public SwimTeam GetSwimTeam(int swimTeamId) 2 { 3 var selectedSwimTeam = (from swimTeam in carpoolEntity.Carpool_SwimTeam 4 where swimTeam.SwimTeamId == swimTeamId 5 select swimTeam).First(); 6 7 return MapSwimTeam(selectedSwimTeam); 8 9 } 10 11 public List<SwimTeam> GetAllSwimTeams() 12 { 13 List<SwimTeam> swimTeams = new List<SwimTeam>(); 14 15 var swimTeamsQuery = (from swimTeam in carpoolEntity.Carpool_SwimTeam 16 select swimTeam); 17 18 foreach(Carpool_SwimTeam carpool_Swimteam in swimTeamsQuery) 19 { 20 swimTeams.Add(MapSwimTeam(carpool_Swimteam)); 21 } 22 23 return swimTeams; 24 } 25  

How do I know that I wrote it right?

Unit Test? Integration Test? I don’t care what you call it – I want to make sure it is right BEFORE I use this as a pattern for the rest of the project.

So I created a couple of unit tests (and remembering to add the app.config to my unit test project)

1 [TestMethod()] 2 public void GetSwimTeamTest() 3 { 4 string expected = "RSA"; 5 string actual = SwimTeamFactory.GetSwimTeam(1).Name; 6 Assert.AreEqual(expected, actual); 7 } 8 9 /// <summary> 10 ///A test for GetAllSwimTeams 11 ///</summary> 12   [TestMethod()] 13 public void GetAllSwimTeamsTest() 14 { 15 int expected = 3; 16 int actual = SwimTeamFactory.GetAllSwimTeams().Count; 17 Assert.AreEqual(expected, actual); 18 } 19  

And got green:

Carpool14

I then wired up the UI

I added a controller to my MVC application

1 public class SwimTeamController : Controller 2 { 3 SwimTeamFactory swimTeamFactory = null; 4 5 public SwimTeamController() 6 { 7 swimTeamFactory = new SwimTeamFactory(); 8 } 9 10 public ActionResult Index() 11 { 12 return View(swimTeamFactory.GetAllSwimTeams()); 13 } 14 15 } 16

Added the connection string to the Web.Config

Added an auto generated View

Carpool15

 

And boom goes the dynamite…

Carpool16

RhinoMocks

I am digging deeper into fakes using RhinoMocks.  I set up a test project that uses a Mock of an InterfaceKit and then sets up some expected return values.  For example:

        [TestInitialize()]
        
public void InterfaceKitTestInitialize()
        {
            
MockRepository mockRepository = new MockRepository();
            interfaceKit = mockRepository.StrictMock<
IInterfaceKit>();
            
Expect.Call(interfaceKit.Address).Return("ValidAddress");
            mockRepository.ReplayAll();
        }

 

And a subsequent test:

        [TestMethod()]
        
public void
 InterfaceKitAddress_ReturnsValidValue()
        {
            
string expected = "ValidAddress"
;
            
string
 actual = interfaceKit.Address;
            
Assert.AreEqual(expected, actual);
        }

 

So far so good – it comes back green.  But then I thought “So what?”  All I am really doing is testing the Mock API.  Unless there is some business logic in the getter, then mocking properties are useless.  I guess you would use a mock over a stub because you can control the number of properties that you need to test – you don’t have to set up a whole  object graph if you just want to test 1 property.

I also noticed that I could use this syntax instead of using Expect.Call:

SetupResult.For(interfaceKit.Address).Return("ValidAddress");

 

 I then tried to venture on to mock a method.  I attempted to add a new line to my initialization method like this:

Expect.Call(interfaceKit.open());
 

However, I am getting some errors:

I then realized that I had a syntax error for parameter-less methods:

Expect.Call(interfaceKit.open).Return(null);

 This works – but I am not testing anything.  So I thought a bit more – why would you even mock a method that does not return a value and does not take a parameter?  Unless there is another dependency that the method needs to run (for example, setting a property of the object before calling the method) and the only way you know if it ran was if you got an exception, there is no point.

Expect.Call(interfaceKit.open).Throw(new PhidgetException(ErrorType.PHIDGET_ERR_CLOSED));

I guess this is what they mean when they say that mocking and unit testing forces you to make a better API.  The Phidget kit does this (open then wait for the event).  I then made a test to check the exception

        [TestMethod()]
        [
ExpectedException(typeof(PhidgetException
))]
        
public void
 InterfaceKitAttachedTest_ThrowsError()
        {
            interfaceKit.open();
            
Assert.Fail("Should never get here");
        }

 and the test passed.  If I wanted to test the value of the ErrorType, I would put it into a try..catch block in the test and inspect the PhidgetException.ErrorType property and remove the ExpectedException attribute.

Autocreate Tests

Dear Microsoft:

When you autocreate a test class, can you include the name of the class in the initialize methods?

        #region Additional test attributes
        [
TestInitialize()]
        
public void MyTestInitialize()
        { 
        }
        
        [
TestCleanup()]
        
public void MyTestCleanup()
        { 
        }

Yuck

        [TestInitialize()]
        public void InterfaceKitTestInitialize()
        {         }
        
        [
TestCleanup
()]         public void InterfaceKitTestCleanup()         {         }

Yum

 

From,

Jamie Dixon

Chaining Tests

I learned something new about tests this morning.  Methods that are called from a test that have an Assert in them will be treated as a test.  For example:

        InterfaceKit interfaceKit = null;
 
        [
TestMethod()]
        
public void InterfaceKitAttachedTest_ReturnsTrue()
        {
            interfaceKit = 
new InterfaceKit();
            interfaceKit.Attach += 
new Events.AttachEventHandler(interfaceKit_Attach);
            interfaceKit.open();
        }
 
        
void interfaceKit_Attach(object sender, Events.AttachEventArgs e)
        {
            
bool expected = true;
            
bool actual = interfaceKit.Attached;
            
Assert.AreEqual(expected, actual);
            interfaceKit.close();
        }

 

Thinking about it, that makes sense – b/c the called method is sharing the stack so the Assert will be called and inspected.

Code Coverage: More Is Less?

I started working on some unit tests for the PhidgetException class.  Following the DRY principles, I re-wrote the constructor logic from this

    internal PhidgetException(int code) : base(string.Concat(new object[] { "PhidgetException ", code, " (", GetErrorDesc(code), ")" }))

    {

        this.desc = "Uninitialized Error";

        this.errType = this.errorCodeToErrorType(code);

        this.errCode = code;

        this.desc = GetErrorDesc(code);

    }

 

    public PhidgetException(string message, ErrorType type) : base("PhidgetException " + type.ToString() + " (" + message + ")")

    {

        this.desc = "Uninitialized Error";

        this.errType = type;

        this.errCode = 0;

        this.desc = message;

    }

 

    public PhidgetException(string message, int code) : base(string.Concat(new object[] { "PhidgetException ", code, " (", message, ")" }))

    {

        this.desc = "Uninitialized Error";

        this.errType = this.errorCodeToErrorType(code);

        this.errCode = code;

        this.desc = message;

    }

 

to this:

        public PhidgetException(string message, ErrorType errorType, int errorCode)
            : base(string.Concat(new object[] { "PhidgetException ", errorCode, " (", GetErrorDesc(errorCode), ")" }))
        {
            if (errorType == ErrorType.PHIDGET_ERR_OK && errorCode != 0)
            {
                this._errorCode = errorCode;
                this._errorType = this.ErrorCodeToErrorType(errorCode);
            } 
            
if (errorType != ErrorType
.PHIDGET_ERR_OK && errorCode == 0)             {                 this._errorCode = ErrorTypeToErrorCode(errorType);                 this._errorType = errorType;
            }

            
if (errorType != ErrorType
.PHIDGET_ERR_OK && errorCode != 0)             {                 int expectedErrorCode = ErrorTypeToErrorCode(errorType);                 if (expectedErrorCode != errorCode)                 {                     throw new ArgumentException("Error Code and Error Type Do Not Match");                 }                 else                  {                     this._errorCode = errorCode;                     this._errorType = errorType;                 }             }            
            
if (message == string
.Empty)                 this._errorDescription = GetErrorDesc(errorCode);             else                 this._errorDescription = message;         }
 
        
public PhidgetException(string message, ErrorType
 errorType)             : this(message, errorType, 0)         {         }
 
        
public PhidgetException(string message, int
 errorCode)             : this(message, ErrorType.PHIDGET_ERR_OK, errorCode)         {         }

 Honestly, the 1st constructor should be marked as private so that you can’t ever get to that ArgumentException, but that is another day’s refactoring.

I then layered some Unit Tests on top of the different constructors to see if my logic worked:

        [TestMethod()]
        public void PhidgetExceptionConstructorTest_Code1_ReturnsPHIDGET_ERR_NOTFOUND()
        {
            PhidgetException phidgetException = new PhidgetException("Test Message", 1);
            ErrorType expected = ErrorType.PHIDGET_ERR_NOTFOUND;
            ErrorType actual = phidgetException.Type;
            Assert.AreEqual(expected, actual);
        }
        [TestMethod()]         [ExpectedException(typeof(ArgumentException))]         public void PhidgetExceptionConstructorTest_PHIDGET_ERR_NOMEMORY_ErrorCode3_ThrowsException()         {             ErrorType errorType = ErrorType.PHIDGET_ERR_NOMEMORY;             PhidgetException phidgetException = new PhidgetException("Test Message", errorType,3);             Assert.Fail("Should Never Get Here");         }

        [
TestMethod
()]         public void PhidgetExceptionConstructorTest_PHIDGET_ERR_NOMEMORY_ErrorCode2_ReturnsErrorCode2AndPhidgetNoMemory()         {             ErrorType errorType = ErrorType.PHIDGET_ERR_NOMEMORY;             int errorCode = 2;             string message = "Test Message";             PhidgetException phidgetException = new PhidgetException(message, errorType, errorCode);             Assert.AreEqual(errorCode, phidgetException.Code);             Assert.AreEqual(errorType, phidgetException.Type);
        }

So far so good. 

I then did a code coverage analysis of my project.  Note that the Code Coverage screens in VS2010 are not the most intuitive, you need to press that cleverly-hidden “Configure” label (why no Button VS team?):

I re-ran the tests and expected some high metrics.

 

47% – WTF?

Drilling down, I saw that I did not check the internal method.  Easy enough to fix, I added

[assemblyInternalsVisibleToAttribute("Com.Tff.Phidget.Tests")]

 to my PhidgetException code file (above the namespace, please), wrote a couple of covering Unit Tests

        [TestMethod()]
        public void GetErrorDescriptionTest_ErrorCode2_ReturnsValidString()
        {
            string notExpected = string.Empty;
            string actual = PhidgetException.GetErrorDesc(2);
            Assert.AreNotEqual(notExpected, actual);
        }
          [
TestMethod
()]         [ExpectedException(typeof(PhidgetException))]         public void GetErrorDescriptionTest_ErrorCodeNeg1_ThrowsException()         {             string notExpected = string.Empty;             string actual = PhidgetException.GetErrorDesc(-1);             Assert.Fail("Should Never Get Here");         }
 

 And now got

 

50%????!!!!  What is going on here?  I have no other methods to cover.  Drilling down, I re-learned the lesson of paying too much attention to Code Coverage.  Check out the code coverage of the 2 lookup methods.

These lookup methods look like this:

 You can see that unless I write 30 covering unit tests for each possible error code and inspect the return value, I will have low code coverage.  A good lesson re-learned.

Testable Phidgets – Follow up from last week

I have given up in creating a one-off interface for the Phidget kit and instead want to see if Rhino Mocks can support mocking concrete classes and give me what I want from an Unit Test.  I whipped up a quick test to see if the open method worked.  Note that I am not using the Assert keyword because I am doing interaction based testing, not state based testing.  I am doing interaction based testing because the method has no return value and the class has no other supporting property that I can use to verify that the method worked.

        [TestMethod()]
        
public void OpenInterfaceKitTest()
        {
            
MockRepository mockRepository = new MockRepository();
            
InterfaceKit interfaceKit = mockRepository.DynamicMock<InterfaceKit>();
            mockRepository.ReplayAll();
            interfaceKit.open();
            mockRepository.VerifyAll();
        }

 

The test passed but 2 thoughts came to my mind:

·         Is this working right?

·         If so, what, in fact, am I actually testing?

Undaunted, I continued on to my next test – mocking the opening the actual Phidget channel.  I set up a unit test the same pattern:

        [TestMethod()]
        
public void
 OpenOutputOnInterfaceKitTest()
        {
            
MockRepository mockRepository = new MockRepository
();
            
InterfaceKit interfaceKit = mockRepository.DynamicMock<InterfaceKit
>();
            mockRepository.ReplayAll();
            interfaceKit.outputs[0] = 
true;
            mockRepository.VerifyAll();
        }

 

When I ran the test, I got a nasty surprise:

Test method VoiceActivatedToaster.Tests.ProgramTest.OpenOutputOnInterfaceKitTest threw exception:

Phidgets.PhidgetException: PhidgetException 5 (Phidget not physically attached.)

 

This is odd – the mock is actually using the real Phidget board – not the mock one that I created.  I then went back to the Rhino Mock documentation and realized that I didn’t tell the mock what to do via an expect call.  I wonder if it is because I am using a concrete class on the left hand side of the equation, not an interface?

 

There seems to be 2 options in front of me.  Build a stub and inject that into the program class.  The stub is based on an interface and I could then control expectations to test my program completely.  Since the classes I am using don’t have any interfaces, I tried to build my own “wrapper” interface.  That turned out harder than I thought so I went to option #2.  Option #2 was to forget the stubs and use a mock that I could control behavior to test.  The examples on-line make sense, but I am having a tough time getting it to work.  I think part of the problem is that the API that I am mocking is not designed to be testable – the Open method does not return a value and there is not a corroborating property to verify and there is not a InterfaceKitDigitalOutput class that I can use – you can only turn the channel on/off via the index on the collection and setting its value to true/false.  The problem with option #2 is that I still can’t create a Mock without an abstract class or an interface.  Here is an example from my last attempt:

        [TestMethod()]
        
public void
 OpenOutputOnInterfaceKitTest()
        {
            
MockRepository mockRepository = new MockRepository
();
            
InterfaceKit interfaceKit = mockRepository.DynamicMock<InterfaceKit
>();
            
Expect
.Call(interfaceKit.outputs.Count).Return(3);
            
LastCall
.IgnoreArguments();
            mockRepository.ReplayAll();
            
int i = interfaceKit.outputs.Count;
            mockRepository.VerifyAll();
        }

 

I’ll keep reading up on Rhino Mocks – but it appears to be a limitation with the framework.

I wonder how much Phidgets would pay me to write a testable .NET wrapper class to their API?   There are 40 classes in it, prob 20 methods each.   If I only had weekends to work on this stuff…

Testable Voice Activated Toaster

In following up to last week’s voice activated toaster, I wanted to work on making my solution more testable.  To that end, I re-read The Art Of Unit Testing:

 I still find his explanation of Mocks versus Stubs confusing.  In any event, I dove right in and added a test project to my solution.  I first realized that Rhino Mocks works either with Interfaces or Abstract Classes – the Phidget API had neither.  I read Brownfield Application Development In .NET:

 and realized that I needed to add an anti-corruption layer to the Phidget API and use an Adapter Pattern to wrap the existing API.

Moving to my code, the 1st stumbling block is that the SpeechRecognitionEngine and Choices classes do not have a defined interface.  I refactored the CreateSpeechRecognitionEngine method to a more testable chunks of code:

 

        public static void SetupSpeechRecognition()

        {

            SpeechRecognitionEngine _speechRecognitionEngine = new SpeechRecognitionEngine();

            Choices _choices = new Choices();

 

            CreateSpeechRecognitionEngine(_speechRecognitionEngine);

            LoadGrammarIntoSpeechRecognitionEngine(_speechRecognitionEngine, _choices);

            _speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);

 

        }

 

        public static void CreateSpeechRecognitionEngine(SpeechRecognitionEngine speechRecognitionEngine)

        {

            SpeechRecognitionEngine _speechRecognitionEngine = speechRecognitionEngine;

            _speechRecognitionEngine.SetInputToDefaultAudioDevice();

            _speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(speechRecognitionEngine_SpeechRecognized);

        }

 

        public static void LoadGrammarIntoSpeechRecognitionEngine(SpeechRecognitionEngine speechRecognitionEngine, Choices choices)

        {

            SpeechRecognitionEngine _speechRecognitionEngine = speechRecognitionEngine;

 

            Choices _choices = choices;

            _choices.Add("Toast");

            _choices.Add("Stop");

            Grammar grammar = new Grammar(_choices);

 

            _speechRecognitionEngine.LoadGrammar(grammar);

        }

 

I then used the adapter pattern to make a testable Phidget API.  I created interfaces for a Phidget, Interface Kit, and a PhidgetException.  I then created Phidget, Interface, and PhidgetException classes that implemented the interface.   I also split out the all of the enums that the API uses into their own class – the values are the same thanks to Reflector.  My solution looked like this:

 

 

I then had some supporting classes to take care of the rest of the API.  The first was the event handlers.  For the sake of keeping the class count down, I put all of the event handers into one class:

 

namespace Com.Tff.VoiceActivatedToaster.Phidget.Events

{

    //Phidgit Events

    public delegate void AttachEventHandler(object sender, AttachEventArgs e);

    public delegate void DetachEventHandler(object sender, DetachEventArgs e);

    public delegate void ErrorEventHandler(object sender, ErrorEventArgs e);

    public delegate void ServerConnectEventHandler(object sender, ServerConnectEventArgs e);

    public delegate void ServerDisconnectEventHandler(object sender, ServerDisconnectEventArgs e);

 

    //Interface Kit Events

    public delegate void OutputChangeEventHandler(object sender, OutputChangeEventArgs e);

    public delegate void SensorChangeEventHandler(object sender, SensorChangeEventArgs e);

}

 

I then added individual classes for each event args.  The Event Subdirectory looked like so:

 

 

Hooking up the events to the Phidget API, I made some good progress.  I then had 3 public fields (sigh) on the Interface Kit: Inputs, Outputs, and Sensors.  My 1st thought was to create interfaces and wrapper classes like I have done so far – but I immediately got a frying pan to the face:

 

 

 

Crap – the constructors are marked internal.  I could not wrap the classes.  I then went to plan B – use Reflector and implement the same code they used.  I then got a frying pan to the back of the head with Plan B when I looked at their code:

 

 

 

They were wrapping their unmanged code so they have these pointers and references all over the place.  I took a deep breath (“OK, I can do this”) and tried to implement.  I tried to reference the unmanaged assembly and got this:

 

 

Plan B is officially dead.  I then went to Plan C – use the Phidget API in my API.  I hated to do it, but I did it.  Here is the relevant code snippet:

 

    public class InterfaceKit : Phidget, IInterfaceKit

    {

        Phidgets.InterfaceKit _interfaceKit = null;

 

        //Have to use the Pdigit API b/c the Constructors are marked as internal

        public Phidgets.InterfaceKitDigitalInputCollection inputs;

        public Phidgets.InterfaceKitDigitalOutputCollection outputs;

        public Phidgets.InterfaceKitAnalogSensorCollection sensors;

 

        public InterfaceKit()

        {

            _interfaceKit = new Phidgets.InterfaceKit();

        }

 

 

I then hooked up my console application to the API and got nothing:

 

 

I then ran out of time: 5 hours of coding for Unit Test – and I have yet to write a single test.  I am just refactoring a poorly-written API to make the classes testable.

 

I’ll keep plugging away.