Concepts

Developing in small circles

By on 17/02/2017

Automatic testing is one of the most important ‘best practices’. But why? We all know that it’s an effort to write them, and more effort to maintain them. Fact is, they can help you writing high quality pieces of your system within a big stack.

Here’s an example stack:

The traditional way is to start working on the different pieces in parallel. Just enough to make a whole ‘stack’ work. Then, step by step, you fill the pieces with all the functionality and types you need. This is quite pragmatic, but during the project, it makes work harder and slowlier, like pulling a trailer that becomes even heavier over time. Some examples:

  • When working on a service endpoint, the database is not available
  • When working on a client endpoint, the service is not available
  • When working on a piece of UI, you need the whole stack up and running, and stored test data
  • When working on a bug, you have to setup the exact dataset that leads to the bug

All these problems make you loose time to setup the environment of the piece you’re working on. And it’s hard to focus on specific tasks and bugs.

If you watch the whole stack, it seems like a long vertical line. And a piece of the stack is a short vertical line. According to MVVM, a component doesn’t know its upper component. So a ViewModel holds no reference to the View. And the database (naturally) doesn’t know anything about the service accessing it. So all the access happens ‘top-down’ – from the UI until the database. Better to say from the User to the database and back. And the user ‘sits on top’ of the UI.

So now you can also see the main flaw in this traditional approach. You need the whole stack implemented and running to be able to test. And you need a User. So the first idea could be ok, let’s automate the User through an UI test – there are lots of frameworks out there. But still – testing happens very late, and only works once all the pieces are running fine.

To improve this whole process, so we can implement and test the different pieces of the stack independently, we have to separate them from their dependencies. So welcome to the world of unit testing you may say. Or even test driven development. To be honest – at this point I don’t care much how you call it, or to follow strictly the rules of unit testing. Me in my daily work, I just try to do this in the way that seems more practical in the moment, and depending on the element of the stack. Here comes my motto that I always try to follow when implementing pieces of software:

CLOSE THE CIRCLE

It doesn’t always have to be automated tests directly. Or unit tests strictly working with mocked interfaces to replace the dependencies of a class. But of course these kind of tests and tools can help us a lot. Important is always to provide the component its dependencies (in the stack underneath) and to interact with it (in the stack from above). So let’s go through the example stack and look at the different pieces.

MainPage

For UI’s my main problem is always not to have data to design it. So why not write a DummyViewModel that implements the same properties, events and commands than the real one? I recommend using an interface to implement both of them. Then you can always be sure not to forget anything for designtime and runtime. Of course this only works if you have a good design tool – like the xaml designer in VisualStudio.

When writing automated UI tests, we should use the opportunity to directly make an end-to-end-test out of it. This happens when the whole stack is available, and includes data creation for each test in the real database. But this comes later.

ViewModel

The ViewModel is often created through a ViewModelLocator that binds it automatically against the view. DependencyInjection makes sure it gets all the pieces it needs. These pieces must be interfaces, passed through the constructor of the ViewModel.

So we write a unit test that creates an instance of the ViewModel with ‘new’. There we pass mocked implementations of the dependencies (for example the IServiceClient). Then, the unit test can set properties (like the view does), calls commands (like the view does) and checks that events are b eing fired (to which the view would listen).

Client

The model would usually just be a data holding class. And if it has more functionality like events and functions, we can use the same approach than for the ViewModel.

The client’s dependency is in our example a http client which allows post and get calls for example. So here we can also write a unit test. And the http client can be mocked with mocking frameworks, where we define its reaction for certain calls. For example when called ‘GET “plant?id=1” it returns a json string “{id:1, name:’tomatoe’}”. Then the unit test calls the client’s function ‘GetPlantType(1)’ and checks that it returns a plant object with the given properties.

WebApp controller

For this guy goes the same than for the frontends’ client. Additionally, it can have filters, for example to only allow logged in users to access an endpoint. So in the unit test, after instantiating the controller, you can pass in a user object which is being used by the filter to verify this prerequisite. This depends a lot in the specific implementation and technology being used.

Of course in that case, you should also write tests that make sure an endpoint call goes wrong if the user is not logged in.

Service controller

Here it gets a little more tricky. How should we mock a database, or the entityframework? I’m sure there are ways, but why go through that trouble?

We could just write a test that sets up a MySql or Sql Express database, create the data scheme by running an EntityFramework migration command and fill defined test data – also with EntityFramework. So we can run the test of the service controller against a real database.

Database

Really – we won’t test the database itself. We should use products and tools that actually work 🙂 No, seriously… the database functionality we have to test, we test directly in the service controller’s unit test. Or in an integration test… just keep reading 😉

So that’s it?

No, not really. What we did now was only testing different units, although not all of the steps were real unit tests. What is missing, is making sure if different pieces work together. Or in other words:

MAKE THE CIRCLE BIGGER

That’s called integration tests. So we can test, for example:

ViewModel and Client

That’s easy, because we’re still within one component. So we could just use what we already created for testing the client (with the mocked http client), and give this to the constructor of the ViewModel. Then we run the same kind of tests against the ViewModel than we did before.

Client and WebApp Controller

This is more tricky already. Because now, we really have to deploy the WebApp in some test environment, to allow real http calls. When running on a Windows machine, we could use the local IIS or IIS Express to deploy the controller. Then we create an instance of the client implementation (using the correct http endpoint configurations) and run the same tests against it than we did when using a mocked http client.

When the WebApp belongs to another environment than IIS, we could write a script that deploys the service to some prepared dev environment.

So I think the strategy for integration tests is pretty clear, and can be applied to other combinations of components. What is missing now, is to test the whole system. This I call end-to-end-test.

For this, we would need 3 big pieces:

  • Deployment of all the pieces. Again, this can be directly in the local environment or in remote machines, using deploy scripts
  • Data! In most cases, we have to generate test data, so the UI has something to show. This can be done through the service endpoint itself, or directly into the database via sql commands. But also, data can be generated during the test itself, by simulated user interaction and input
  • The UI test itself. This depends completely on the technology the UI is made of. I won’t start a list of them, because it would be endless, and seem to show favorites. But an important difference in automated UI tests is if they are coded or recorded. Coded tests usually take more time, but can be more precise and detailed. Recorded tests, where you or a tester records his interactions, can often be made faster and easier, and include more human behaviour (like delays when typing in). Often, the best way is to use a combination of the two.

So, this was a theoretical description of developing software in circles, like I like to define it. Of course, I didn’t reinvent the wheel with that. But for me, the important lesson in this is to show, that testing can be a huge tool that makes programmer’s life easier and more efficient. It’s not about satisfying metrics, your technical lead or the product owner! It’s about you, your work and the quality of the product. Only then, all the test- and mocking-tools become really powerful!

In following posts, I’ll bring you practical examples. And I’ll also go into the subject of how tests can help you maintaining your system. Often it seems that existing tests are just standing in the way when trying to enhance functionality or fixing bugs. But that’s just one side of the coin.

I recommend you always to keep my mantra in mind. It will help you in the moment, and in the future. Just find your own way to include it in your work.

CLOSE THE CIRCLE

So long… I hope you enjoyed this article and it helped you to see some things more cleary. So long…

HAPPY PLANTING

TAG