Test a Controller which have a ServiceDependency

Topics: CAB & Smart Client Software Factory
Jan 8, 2006 at 5:57 PM
originally posted by: jburtch

When you run it in the GUI, your Controller and View classes are operating within the CAB environment. By this I mean that you have some WorkItem that adds these items into the ManagedObjectCollections of the WorkItem. The WorkItem internally uses the ObjectBuilder to create the objects and initialize the properties as specified in the attributes that adorn the properties.

Inside your unit test, these are just objects and are not getting any automatic property assignment (because there is no ObjectBuilder in play.) In most cases this is a good thing. Inside your unit test, you can assign a MockService to the GPS property of the controller and then you can better control the inputs of the controller as you have the outputs. In this scenario where all other objects are mocked, you really are testing your GPSController only.

Justin
Jan 9, 2006 at 3:12 AM
originally posted by: yarezki

Justin,

You are right I, however, believe that if you cannot test something there is a flaw in the design. Most recently Peter Provost gave a webcast on TDD Pair Programming Game. He tests the GUI in the same way I showed, I therefore beleive there must something I could add to my tests so that the object that have a srerviceDepency in the controler could be initialised.

Thanks
Yazid
Jan 9, 2006 at 8:50 AM
originally posted by: jburtch

In the VSTS Test project for CAB, there is an object called TestableRootWorkItem. Create one of those and then add the view and controller into it's Items collection. That will get the ServiceDependency to be detected and initialized. Though the initialization you are doing by adding this WorkItem into the mix means that you're testing the CAB dependency injection framework and without a little manipulation of configuration of services, you are also testing your service. Just means that if the test breaks, you have a couple of classes you have to investigate.

Justin Burtch
Jan 12, 2006 at 7:31 AM
originally posted by: PProvost

If you want to see how we're doing TDD with WorkItems in the SC-BAT project, head on over to http://codegallery.gotdotnet.com/scbat and download last week's build.

(BTW, we're doing weekly published builds right now on SC-BAT, so you can see what we're doing as we do it.)
Jan 14, 2006 at 7:17 PM
originally posted by: amishah_2001

Hi!
How are you accessing controller.View from the view even if there is no any property of View in the controller class.
CreateNew
public GPSController Controller
{
set { controller = value; controller.View = this; }
}

Can you please reply me as I am also looking for the same type of constructor which takes view as a parameter but i donot know how to set that without property from the CreateNew attribute method as u have done above.

Thanks
Jan 15, 2006 at 2:49 AM
originally posted by: yarezki

In the Lab 1 hands on I created an interface:

public interface IGPS
{
string Latitude { get;set;}
string Distance { get;set;}
}

I then got the GPSView to implement IGPS and I also created GPSController.

public partial class GPSView : UserControl,IGPS
{

private GPSController controller;

CreateNew
public GPSController Controller
{
set { controller = value; controller.View = this; }
}

public GPSView()
{
InitializeComponent();

}

private void cmdGetDistance_Click(object sender, EventArgs e)
{
controller.CalculateDistance();
}

private void cmdGetLatitude_Click(object sender, EventArgs e)
{
controller.CalculateLatitude();
}

#region IGPS Members

public string Latitude
{
get { return txtLatitude.Text;}
set { txtLatitude.Text = value;}
}

public string Distance
{
get { return txtDistance.Text; }
set { txtDistance.Text = value; }
}

#endregion

}

// GPSViewController

public class GPSController
{

private IGPS _view;
public IGPS View
{
set { _view = value; }
}
private IGPS _view;
private WorkItem parentWorkItem;

ServiceDependency
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
}
//TODO:
private IGPSService gpsService;
ServiceDependency
public IGPSService GPS
{
set { gpsService = value; }
}
public GPSController()
{
}
public void CalculateDistance()
{
IDistanceCalculatorService calc = parentWorkItem.Services.Get<IDistanceCalculatorService>();
_view.Distance = calc.ComputeDistance(gpsService.GetLatitude(), gpsService.GetLongitude()).ToString();

}
public void CalculateLatitude()
{
_view.Latitude = gpsService.GetLatitude().ToString();
}

Nice and neat I think, I have moved all the business logic to the controller (i.e. GPSController). Now what I want is test GPSController so I created a MockView:

public class MockView:IGPS
{

#region IGPS Members

private string _latitude;
private string _distance;
public string Latitude
{
get { return latitude;}
set { latitude= value;}
}

public string Distance
{
get { return distance; }
set { distance= value; }
}

#endregion

}

I then created a UnitTest as follows:

TestClass
public class GPSViewFixtures
{

public GPSViewFixtures()
{
}
TestMethod
public void CalculateLatitude()
{
GPSMockView view = new GPSMockView();

GPSController controller = new GPSController();
controller.View = view;

controller.CalculateLatitude();
Assert.AreEqual("42", view.Latitude);
}
}

When I call controller.CalculateLatitude(), I get gpsService = null when I run it from a test project. However, when I run it normally (i.e. from the GUI) everything works. Is there anything I could add so that gpsService is not null.

Thanks
Yazid
Jan 15, 2006 at 3:32 AM
originally posted by: yarezki

In the view I have

public partial class GPSView : UserControl,IGPS
{

private GPSController controller;

CreateNew
public GPSController Controller
{
set { controller = value; controller.View = this; }
}

... // More code

}

In the GPSController I have:

public class GPSController
{
private IGPS _view;
public IGPS View
{
set { _view = value; }
}
public GPSController()
{
}
// More code

}

I am accessing it with a setter.

It all works but when I try to UNIT test it the objects which a have a service dependency are null and If I ran it from the GUI it works.


Yazid