Showing posts with label Test. Show all posts
Showing posts with label Test. Show all posts

Tuesday, June 3, 2014

About the „Is TDD Dead?“ discussion

It did not take long after Agile died that TDD joined its party. If you havent noticed, David Heinemeier Hansson put up quite a rant against TDD on his blog leading to a lot of discussion - also on Twitter. Finally they ended up doing a live online discussion regularely featuring Kent Beck, Martin Fowler and David not (yet) involving the TDD advocate Robert C. Martin aka uncle bob. If you haven't watched it live, here is the initial 30min discussion of the series on Youtube. I really recommend the whole series.

I think this topic and the ongoing discussion is very valueable to our craft because it is the kind of questioning and critical thinking that evolve what we do and how good we are at it. Even if we have a strong faith in something, we should not be afraid to question it, ever.

I get davids points, however i do not entirely agree with all of his concerns. I want to share my thoughts in this blogpost.

„Test induced design damage“
A good design is a design that makes the software easy to change. I think this is something we all agree about. While TDD generally puts a lot of good pressure on your design, it can still make the code hard to change if you apply a high level of isolation, lots of mocking, and a high test-granularity. In this case refactorings and other changes will force us to touch a lot of test-code also. So i've come to the conclusion that its best to apply an individual level of test-isolation/granularity that suit the current requirements. Complex and/or long-lived software might take much value of a strict TDD approach, while simple and/or short-lived software might take more value of a more pragmatic approach. I've happened to experience lots of applications that were so big yet simple that "collaborating-units-tests" with reduced mocking and integration tests were just perfect. The value of this approach was that it was very easy to change/refactor production code without touching test-code. Still, the tests provided 100% functional coverage. So i think that design damage is not induced by tests or tdd, but by bad decisionmaking. Testing is engineering. Look for advantages, make tradeoffs. Trying to minimize mocking can definitely pay off. The advantages of a high test-isolation-level/granularity are
  • a very accurate fault-feedback,
  • and that every part of the code is executed just as much as it had to, leading to a faster test-suite

„To Test first, or not to Test first“
The point is, you do not want to verify if the code is working manually. You'd have to do it way too often, and it would just take too long. You want to be able to fiddle with the code, and do small changes frequently, without having to try everything out manually. You want to do it automated, and the feedback should be instant. So i see no point in 1. writing code, 2. trying it out, and then 3. writing a test. Why not write the test in the first place? Also, we tend to be very flaccid on writing a test for something that we have found to be working, because we tend to become euphoric about our success very quickly which makes us tired of digging in details. Other than that, the actual writing of the test first forces us to think about the problem to an extent that makes us recognize details, that we hadn't yet thought of. These details are better to be known before we start writing production code.

„TDD is so widespread nowadays“
I was laughing when i noticed that there are actually people who believe that everyone does tdd nowadays. Sadly, TDD, or lets say developer testing is in fact unused and/or undiscovered in many places. I've happened to see it missed in programming education and also software companies. Sometimes, it was even unwelcome by certain customers. If you were using any kind of developer testing in these places, you were a pioneer. There is still plenty of work to do on this topic.

The bottom line is, automated developer testing is good. We need it. We were silly if we didn't. The question is just: "How?". And this is where engineering comes in.

Tuesday, October 15, 2013

Boost your development speed

I'm really pragmatic on this. To go faster, you need to avoid the things that slow you down. These blockers may vary from developer to developer, but some are pretty common. In this post i will elaborate on the more common ones. Before i do so i want to remind you that to improve, we might need to unlearn in the first place.
Tip: Sometimes, the greatest achievement in improving is to successfully unlearn.

Are you using your Mouse?

Don't let your mouse slow you down. If you are not using all of your fingers typing, you might want to stop reading here and go over to a typewriting course. The following recommendation also assumes that you are using a feature rich editor like vim or an ide. Every single time you move your hand over to your mouse for a click there is a keyboard shortcut for the exact action that you are not aware of, or not used to. You want to learn these. It's really not that hard,  you'll get used to it faster than you'd think. Just begin by putting your mouse over to the other (or wrong) side of your keyboard. You're now forcing yourself to think every time you want to click. When this happens, remember to think of a possible solution using your keyboard. Don't know any? Ask your friends or search the internet (yes, you can use your mouse for that). BUT: Do not use your mouse for what ever action you wanted to perform. After following these simple rules for a few days, you'll notice how irrelevant your mouse has become. If you start feeling comfortable using your keyboard only, you could even try some sessions with your mouse plugged out. Mastering your keyboard will significantly boost your development speed.
Tip: You could print out a list of your IDEs shortcuts and use it as a cheatsheet

Reduce the Time debugging

Debugging costs an awful lot. It's not rare that we end up hunting a bug for hours or even days. Quite often we engage multiple co-workers to solve it. This is really not a scenario we want to be in, since its not only expensive, but also depressing. How can we avoid such a scenario? Pretty easy. Just separate the software into pieces that work in isolation, and write automated tests that cover the components behaviour. This way, we can easily distinguish the component the bug is actually sitting in, and the debugging will become a cinch. The better the tests, the easier to find the bug. However, you wont write good tests, if the system that you are testing is already done and working. You'll assume that there is no additional value of writing thoughtout tests, when it's already working. Overcome this dilemma by writing your tests BEFORE the implementation. As a side effect, this will also help you coding in many ways. You want to treat your tests as first class citizens and as what they are - at least as important as your implementation. Think of a blacksmith who's casting metal into a mold. What would be more important for him. The mold, or the first sculpture coming out of it? You know the answer. And guess what... the tests are your mold. I don't care what you call it. TDD, BDD or whatever. Just automate tests to cover your softwares behaviour, write them before the implementation, and treat them as what they are - at least as important as your implementation.
Tip: When using TDD, you want to use a shortcut to quickly navigate between the test and its implementation. I've bound it to Alt+T


Reduce the Time reading code

I can't stress this enough: You spend more time reading code than writing code. Believe it or not, while implementing a new feature or solving a bug, you repeatedly read code. You read code before you start writing new code, you read code multiple times inbetween writing code, and you read code after you have written it. Reading a 50 line method is pretty time consuming. Thus you want to make reading as easy and smooth as possible. Write self explanatory code with good names and short methods. And Don't Repeat Yourself. Who wants to read anything twice? Invest some time on this, and it will pay off.

Improve your search skills

This is an important one. A searchengine has become the most important development tool. It is even more important than your ide. You can do anything without your ide if you can find out how, but you cannot do anything with your ide if you dont know how. You are probably googling regularely, so it's worth improving. Improve your searchterms. Anticipate helpful words like 'how to' or 'problem'. Try different variants and quote important words and sentences. If you keep getting bad results of a common subject or website, filter them out using a preceeding minus. Here are some examples:
  • while c -do -c++
  • SomeException -helpme.com
  • How to "clean code"
If you keep getting out-dated information, limit your search to the last month/year. This can easily be done in the search options. On stackoverflow, do not always read the first post since its usually a question and code thats not working. Scroll down to the answers with the most upvotes. They are worth reading. Bookmark the sites/docs that you are using regularely. You don't want to search them over and over again. Also, consider code search engines (Examples here and here).


Focus & Calm

You want to get into and keep a good focus when working on a task. Get into your flow and do not allow disruptions. Several disruptions can easily cost you an hour or two each day. Use headphones in louder environments, and communicate that you'll be available for questions a little later. Focus requires a clear mind. Make sure you don't have to remember too much stuff. You don't want to be afraid of forgetting things. If you can feel the fear to forget, write that thing down - so you can forget. Also, don't work on too many different tasks/projects at the same time. One is perfect, two is ok. More is probably just slowing you down. I've happened to work on 7 different projects a single day. It's really really dragging from you. Also, stay calm even in the most stressful situation. Huddling just slows you down even more.

Invest in Hardware

Hardware is cheap, workhours are not. Good hardware will save lots of time in the long term. An SSD that makes you boot within seconds and loads everything real quick, saves at least 10 minutes a day which is 40 hours a year. Same goes with ram and cpu of course. Also, screensize really matters. Choose a large monitor to be able to see everything without resizing/scrolling windows/panels. I personally feel comfortable with ~27". You can speed up many tasks using two monitors also. Web development would be such a task for example.
Tip: 16:9 is standard nowadays but not quite optimal for coding. The higher the screen, the more lines of code you see. Try a 16:10 instead.

Optimize your Workflow, Question your Tools

It depends on what you are working on, but the goal stays the same. You want the most lean workflow and you will constantly have to reevaluate and improve it. For example: If you are working on a Java Webapp, you want to be able to quickly get feedback without redeploying. You can do this by using a class-reloader like spring-loaded or JRebel, or use the Play Framework which does not require redeployments at all due to its architecture. You could also question the language. Is there something else than java that could be more appropriate? Automate everything: testing, building, deployment, notifications. Consider rapid prototyping if you are in the early stages of a project.


Saturday, March 2, 2013

Selenium Test Automation with Maven

Today i want to help you manage your Automated GUI Tests (Selenium) better. In the past i have seen many different ways people handle this. Some people just write those plain HTML TestCases with Selenium-IDE, store it somewhere on the HDD and run manually when needed. Others dont even use Selenium-IDE. They write pure Java for Example, and automate their execution with JUnit. My todays solution lies inbetween.

Precondition

  • I want plain HTML TestCases, created with Selenium-IDE. So that someone with little Programming skills can still create them.
  • I want these GUI Tests to be run automatically in my Build process, so my CI-Tool can notify me on errors.
  • I also want all TestCases under Versioncontrol in my Projects Repository since the Tests grow with the Source.
  • I want the most little effort with the highest outcome. So i dont want to export JUnit Tests out of my HTML TestCases since it would be kind of a Duplication - and i want to stick to the DRY Principle.

Solution

First of all i create a Folder in my Project for the Selenium-Tests.

Folder Structure
        1. TestSuite
        2. SomeTest1
        3. SomeTest2
  1. pom.xml

Example TestSuite

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
    <title>Test Suite</title>
</head>
<body>
<table id="suiteTable" cellpadding="1" cellspacing="1" border="1" class="selenium">
    <tbody>
    <tr>
        <td><b>Test Suite</b></td>
    </tr>
    <tr>
        <td><a href="./SomeTest1.html">SomeTest1</a></td>
    </tr>
    <tr>
        <td><a href="./SomeTest2.html">SomeTest2</a></td>
    </tr>
    </tbody>
</table>
</body>
</html>

 

Example Test

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="selenium.base" href=""/>
    <title>SomeTest1.html</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
    <thead>
    <tr>
        <td rowspan="1" colspan="3">SomeTest1</td>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>open</td>
        <td>/</td>
        <td></td>
    </tr>
    <tr>
        <td>waitForElementPresent</td>
        <td>//div[@id='someId']</td>
        <td></td>
    </tr>
    <tr>
        <td>click</td>
        <td>css=button.create</td>
        <td></td>
    </tr>
    <!-- Some Steps -->
    <tr>
        <td>assertText</td>
        <td>
            //div[@id='someId']
        </td>
        <td>${expectedText}</td>
    </tr>
    </tbody>
</table>
</body>
</html>

 

Setup WebServer

So i have my TestSuite in place. But how do i run them? Most importantly, it should run within the Maven Build Process, so it will also run on Jenkins-CI or whatever. As we are testing against a real running WebApp this is an End-to-End-Test per definition. In Maven we have the opportunity to run such Tests within the integration-test Phase. If you want to learn more about the Maven Build Life-cycle and its phases check out this. So we need some kind of WebServer to run our WebApp, otherwise the tests wont work. The WebServer should be started before the integration-test phase, and be stopped afterwards. We could Use Tomcat7 or Jetty for example. In this example i will use the tomcat7-maven-plugin. I configure my pom.xml to start Tomcat7 pre-integration-test.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.0</version>
    <executions>
        <execution>
            <id>tomcat-run</id>
            <goals>
                <goal>run-war-only</goal>
            </goals>
            <phase>pre-integration-test</phase>
            <configuration>
                <port>8080</port>
                <fork>true</fork>
            </configuration>
        </execution>
        <execution>
            <id>tomcat-shutdown</id>
            <goals>
                <goal>shutdown</goal>
            </goals>
            <phase>post-integration-test</phase>
        </execution>
    </executions>
</plugin>

If you are running multiple Projects on a CI-Server you might consider using a different Port-Number for each Project.

Finally: Run the Tests

Last but not least we need to run the tests. Luckily there is this selenium-maven-plugin available that does the job.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>selenium-maven-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <browser>*firefox</browser>
        <suite>src/test/selenium/TestSuite.html</suite>
        <startURL>http://localhost:8080</startURL>
    </configuration>
    <executions>
        <execution>
            <id>run-selenium-tests</id>
            <phase>integration-test</phase>
            <goals>
                <goal>selenese</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Now,  whenever we execute mvn clean verify or even mvn clean install in console, the Tests are run and reports are stored within the target directory. This will also be done by your CI-Tool.

Conclusion

We do have a complete and clean Setup.
  • We have a place to store our Tests,  
  • They are within the Sourcecode and Version control
  • They can be run automatically by CI-Tools
  • Even Non-developers can add new TestCases
Btw: Dont give up if something is not working as intended. Selenium seems a little buggy, and some times you have to dig a little to solve problems. But it really works, i figured it out.
I hope you enjoyed this Guide. Greetings.