Long time since I last wrote here, but if you’ll take a look at the draft of my book, you’ll see why… By the time I’m writing this post I wrote 80 pages in the book, and hopefully when you read it there will be even more.
Anyway, today I want to share with a screen cast that I recorded with one of my clients, in which I show to a new automation developer on the team how to create a new automated test and explain how I’m going about building a highly maintainable framework. The video is in Hebrew (sorry non Hebrew speakers. At least you may find the rest of this post interesting and maybe just by watching you’ll something, except of Hebrew :-))
Before we started the recording, I gave him an introduction to my approach of writing tests and framework, but because we didn’t record this conversation, I’ll explain it here again. I suggest that you’d read this introduction first and then watch the video. The link to the screen cast is at the end of this post, but I really encourage you to read this intro first…
When I come to create an automation framework for a new project, I first start with few questions that help me better understand the system, the expectations from the automation, etc. I won’t go too much into details here, but among other things I try to get answers for the following questions:
- What the main purpose of the application under test?
- Who are its users?
- What are the main components and interactions in the system? In other words – what’s its architecture looks like?
- What are the main scenarios?
These questions help me decide how to architect the automation, mainly with regard to isolation, and also help me choose the first tests that will be implemented.
Writing the first test
It may be a surprise for you, but I don’t start by writing any infrastructure code. Instead I start by writing a test. When I implement this test, I build all the necessary infrastructure that this test needs (This is the main concept that I demonstrate in the video). After doing so for the first test, I write another test, adds any missing parts in the infrastructure to support this test, and refactors to remove any duplication that I might have created in the process. I repeat this process with more and more tests, and incrementally broadens the infrastructure to support all of the tests, while constantly refactoring to remove duplication.
This “remove duplication” part is extremely important in making the tests and the infrastructure highly maintainable. If you do it correctly, it means that practically any change that you have to make at any time, you can make it by changing only in one place! It also makes the code more reliable because its easier to verify any such change.
Composing the test scenario in a scientific manner
Before any test that I write in code, I first write it down in a free text format. But I don’t just take a test scenario that some manual tester gave me because there are different considerations between manual and automated tests (I won’t go into details here, but you can read more about it in my book). Instead, I’m trying to compose the test in a way that corresponds to the scientific method. Specifically, I design the test as a scientific experiment such that it will either prove or disprove a claim about the behavior of the application. Obviously, if the test passes it proves the claim, and if it fails, it disproves it. The claim itself is the requirement which the test verifies.
This method results in many small and dedicated test scenarios instead of few big “hairy” ones, which in turn also makes the automation system easier to maintain and to investigate failures.
So first I start by phrasing the claim that I want the test to prove. Then I’m thinking what we be the experiment that will prove or disprove this claim. Note that this way of thinking not only make it much more interesting to write tests, it also makes the tests much more valuable as they test what’s really important!
Then I’m writing down the steps of the experiment, but only in high-level, business terms, hiding any details which are not relevant for the experiment. This help us focus on the important aspects, and later when we translate the scenario into code, it will help us organize the code in a more reusable and maintainable way. I write one sentence per line.
Putting things in context
Just before I’m translating the sentences into code, I write beside each sentence a context to which it belongs. This is an intermediate step between the textual representation of the test scenario and the code, which will soon help us create the code in a modular and object-oriented approach, which eventually also make it easier to maintain.
Writing the code
We’re now ready to start coding. But there’s a method to do that too:
First I write the code in the IDE, but as a pseudo-code, which uses classes and methods that are not defined yet. The code in the test should look very similar to the textual representation, but in a valid C# syntax. While we write code which is syntactically valid, it’s not compilable in this stage because it refers to classes and method that are not declared yet.
Only after I completed writing the test method in a way that looks very similar to the text (which makes the test very readible!), I start to create skeleton classes and methods that will make the code compile. However, I still don’t really implement any method.
When the code compiles, even though I haven’t implemented any of the methods, I run the test to watch it fail on the first “NotImplementedException”. Only then I write the code for that method, and run again. I repeat this process until the test passes.
Along the way or at the end, if I encounter any duplication I refactor it so that there’s no duplication. I use Resharper extensively to help me with that.
Enough talking. Click here to see the screen-cast!
Many thanks for Evitar Maman (the other voice you hear on the recording) which encouraged me to record and publish this screen cast!