The solution at the moment only contains a couple of short tests, that cover the complete cycle of a project and hiring staff. Nevertheless it’s a complete integration test over the whole system covering at least the most important areas of the application.

This is the test – it’s quite self-explaining I believe (this is one of the biggest advantages of this approach – tests are fairly easy to write and to read – and therefore to maintain):

[TestMethod]
public void TestBasicProject()
{
   // create system
   system = new ATBSystem(true);
 
   // click on the "Project Offers" button
   system.MainWindow.ProjectOffersCommand.Execute(null);
 
   // make sure that the correct page is displayed
   Assert.IsTrue(system.MainWindow.CurrentPage is VProjectOffersPage);
   // get the page
   VProjectOffersPage projectOffersPage = system.MainWindow.CurrentPage as VProjectOffersPage;
 
   // verify that the correct date is displayed
   Assert.AreEqual("Tuesday, 1 Jan 1980", system.MainWindow.CurrentDate);
 
   // get the number of project offers
   int num = projectOffersPage.Projects.Count;
   // the last one is a special test project that we use for the test
   VProject project = projectOffersPage.Projects[num - 1];
 
   // TODO: check project properties
 
   // click the "Take" button
   project.TakeCommand.Execute(null);
 
   // there should be one project less now
   Assert.AreEqual(num - 1, projectOffersPage.Projects.Count);
   // and on the project page we should have one project now
   Assert.AreEqual(1, system.MainWindow.ProjectsPage.Projects.Count);
 
   // goto to hire page - click on the "Hire Staff" button
   system.MainWindow.HireStaffCommand.Execute(null);
   // make sure that the correct page is displayed
   Assert.IsTrue(system.MainWindow.CurrentPage is VHireStaffPage);
   // get the page
   VHireStaffPage hireStaffPage = system.MainWindow.CurrentPage as VHireStaffPage;
 
   // get the number of persons
   int personCount = hireStaffPage.Persons.Count;
   // the last one is a special test developer that we will use in this test
   VPerson myDeveloper = hireStaffPage.Persons[personCount - 1];
   // click the "Hire" button
   myDeveloper.HireCommand.Execute(null);
   // there should be one developer less now
   Assert.AreEqual(personCount - 1, hireStaffPage.Persons.Count);
   // and one more on our "Staff" page
   Assert.AreEqual(1, system.MainWindow.StaffTab.Staff.Count);
 
   // goto to project page
   system.MainWindow.ProjectsCommand.Execute(null);
   // make sure that the correct page is displayed
   Assert.IsTrue(system.MainWindow.CurrentPage is VProjectsPage);
   // get the page
   VProjectsPage projectsPage = system.MainWindow.CurrentPage as VProjectsPage;
   // get the first (and only) project view
   VProject newProject = system.MainWindow.ProjectsPage.Projects[0];
 
   // select our developer; that makes him part of the project
   newProject.SelectedPerson = 0;
 
   // he must be a member now
   Assert.AreEqual(1, newProject.Members.Count);
 
   // get our developer as member
   VPerson developerAsMember = newProject.Members[0];
   // select business part of project for our developer
   developerAsMember.CurrentProjectTask = 4;
 
   // start the sim
   system.MainWindow.ContinueCommand.Execute(null);
   // simulate an update
   system.Update();
 
   // ...
 

Automation concept

When testing manually, the more complex the application becomes, the longer it takes to click through the application to get to the point where I’d like to test something.

For example: I wanted to test if the message boxes at the end of a project are displayed correctly: the success box when the project was successfully finished, the “too many bugs” box when there were too many bugs for the customer and the “overdue box” when the project took too long. That means that I have to click through the whole procedure of taking the project, switching to the “Hire staff page”, hire the person I want, switch to the project page, select the person to make him a member etc. pp.
All together it takes 2-3 minutes to reproduce all those steps (especially because of waiting for the individual tasks to finish) – again and again. And the more the application grows, the more complex test scenarios you will encounter and the more time development and testing will take.

It would be cool if there were a kind of automation mechanism to play all these pre steps automatically up to that point where I want to test something…
The View Model concept allows it to automate the application fairly easy. It’s basically the same as writing an integration test but just from inside the application itself. Since the complete view model interface to control the application is made public, so the view can operate on it, it’s also possible to automate the application via the same interface from the application itself.

I created an Automator class that runs a test case to automate the application; this for example is the code that simulates the “untested” part of a project: (the _dispatcher is the connection to the main system.)

public void RunUntested()
{
   // click on the "Project Offers" button
   _dispatcher.MainWindow.ProjectOffersCommand.Execute(null);
 
   // the last one is a special test project that we use for the test
   VProject project = _dispatcher.MainWindow.ProjectOffers.Projects[_dispatcher.MainWindow.ProjectOffers.Projects.Count - 1];
   // click the "Take" button
   project.TakeCommand.Execute(null);
 
   // goto to hire page - click on the "Hire Staff" button
   _dispatcher.MainWindow.HireStaffCommand.Execute(null);
   // the last one is a special test developer that we will use in this test
   VPerson person = _dispatcher.MainWindow.PersonOffers.Persons[_dispatcher.MainWindow.PersonOffers.Persons.Count - 1];
   // click the "Hire" button
   person.HireCommand.Execute(null);
 
   // goto to project page
   _dispatcher.MainWindow.ProjectsCommand.Execute(null);
 
   // get the first (and only) project
   project = _dispatcher.MainWindow.ProjectsPage.Projects[0];
   // select our developer; that makes him part of the project
   project.SelectedPerson = 0;
 
   // get our developer as member
   person = project.Members[0];
   // select OS part of project for our developer
   person.CurrentProjectTask = 2;
 
   // while we not reached 100 %
   while (project.CurrOsSkill.AmountAsInt < 100)
   {
       // simulate an update
       _dispatcher.Model.ForcedUpdate();
   }
 
   // select database part of project for our developer
   person.CurrentProjectTask = 3;
 
   // while we not reached 100 %
   while (project.CurrDatabaseSkill.Amount < 100)
   {
       // simulate an update
       _dispatcher.Model.ForcedUpdate();
   }
 
   // select UI part of project for our developer
   person.CurrentProjectTask = 1;
 
   // while we not reached 100 %
   while (project.CurrUiSkill.AmountAsInt < 100)
   {
       // simulate an update
       _dispatcher.Model.ForcedUpdate();
   }
 
   // select business part of project for our developer
   person.CurrentProjectTask = 4;
 
   // while we not reached 100 %
   while (project.CurrBusinessSkill.AmountAsInt < 100)
   {
       // simulate an update
       _dispatcher.Model.ForcedUpdate();
   }
}
 

Note: As you can see, the automation code is pretty much the same as the integration test. To be precise: it should be the same code and it will be the same code in the next version. The only difference is, that the integration test needs the initialization of the system which is not required with the Automator because it runs inside the application itself. Furthermore the test uses Asserts, which are useless inside the application.

The funny thing with this approach is, that you can visually follow the automation because the views always represent the current view model state – it’s like a macro.
Running this automation script now takes about a second – in comparison to 2-3 minutes when done manually; that is a quite simple way of saving lots of time – day by day.
Having unit tests does not mean that there are no bugs, so if you encounter some, please let me know.

The game’s main page you can find here: All Those Bugs Page