There are various levels of testing in software. The one most people are familiar with (including software testers) is testing done through the user interface, which is basically using the application at the end of a software development cycle and finding out whether it does what it is supposed to do. It’s a practice that is easy to understand and natural to do. Most of us have mobile devices or computers at home and in that sense we all understand how to test apps on the UI at some basic level. We explore the functionalities apps say they deliver and we decide for ourselves whether we think those promises are being kept or not. We feel good when everything works well or we feel bad when it is difficult to use the app (and maybe never use that app again). That said, software testing is not limited to the user interface.
The more experienced testers understand that testing is easier to perform and more valuable when it is done early in the software development process, making sure that we are doing the right things and are doing things right, even though we know we can’t test everything all at once. Bugs found before shipping are cheaper and easier to solve than bugs found later. Quick and early feedback is ideal. But to accomplish testing early in the software development process means that testers actually need to understand how software is built from code, not just the code itself and how various pieces of code integrate with one another but how programmers write code too. Like everyone else, programmers are people and human and are fallible. People make mistakes, and people can continue to make mistakes even if they work on projects carefully, because that’s how people and the things they build grow. That’s why testing needs to happen as early as possible. That means testers working alongside programmers in putting systems in place that tests the application simultaneously while it is still being written, even when there is no user interface to see yet. That means recognizing where and when mistakes happen, whether in code or habits or processes, and making it easy to spot them when they happen again. Testing in the user interface will never disappear but we can do better than restricting ourselves to just testing at the end.
Last Wednesday afternoon I anxiously asked my boss for permission to make changes on our application code repository. I said I wanted to try fixing some of the reported bugs listed on our tracking system, if there are no other resources available to pass them to. I made a case about myself not posing any problems because of the code review process built into our repository management tool, that there’s no reason for me to merge any changes without getting feedback from a senior developer first.
He smiled at me and gleefully said “Go ahead. I’m not going to stop you.“, to which I beamed and heartily replied “Thanks, boss!”
This is a turning point in my software testing career, to be able to work on the application code directly as needed. It is actually one of my biggest frustrations – to not be able to find out for myself where the bug lives in the code and fix them if necessary. It’s always a pain to be able to do nothing but wait for a fix, and for a fix to be dependent on the resources available. In my head I think that I’m available and maybe I can do something, but I don’t explicitly have access to the application itself and the code that runs it so I can’t do anything until I have the rights to do so. That’s how it always been. Software testers are often not expected to fiddle with code, at least in my experience, especially in the past where automation was not yet known to be useful as a testing tool. Now that I have the skills and the permission to work on the application repository, I feel that my reach for making an impact on application quality has now expanded remarkably well.
Now bug-fixing is not software testing work in the traditional sense. But I figured there’s no harm in trying to fix bugs and learning the nitty-gritty details of how our legacy applications actually run deep in the code. I believe that learning technical stuff helps me communicate better with programmers. It helps me test applications in a more efficient manner too. Of course I have to consistently remind myself that I am a software-tester-first-programmer-second guy and have to be careful not to fill my days playing with code and forgetting to explore our applications themselves. That said, there are ideas I really want to experiment within our software development process, towards the goal of improving code quality and feedback, and I can only tinker with those ideas inside the application repository itself. Dockerized testing environments, code linting, and unit tests are three things I want to start building for our team, ideas that I consider to be very helpful in writing better code but has not been given enough priority through the years.
I think I’m still testing software, just extending the knowledge and practice of the various ways I perform testing.
To answer a question about exploratory testing, Alister Scott recommends testers to read a Margaret Heffernan book, titled “Willful Blindness“. He tells us that we have to be less blind when we’re exploring in order to find bugs in systems under test. We have to keep on looking, we have to continuously question things, we have to choose to know and understand how the system works. Reading Margaret’s book has helped me realize what being willfully blind meant and how we become blind without noticing. It has helped me be more aware of the different ways I can misjudge things, and thus helps me get better. Cognitive limits, biases, division of labor, money, hierarchy, relationships, feelings of belonging or ostracism, all these and more play a part in how we behave in various situations. They affect how we perform our software testing too.
- We can’t notice and know everything: the cognitive limits of our brain simply won’t let us. That means we have to filter or edit what we take in. So what we choose to let through and to leave out is crucial. We mostly admit the information that makes us feel great about ourselves, while conveniently filtering whatever unsettles our fragile egos and most vital beliefs.
- Most people marry other people very like themselves: similar height, weight, age, background, IQ, nationality, ethnicity. We may think that opposites attract, but they don’t get married. Sociologists and psychologists, who have studied this phenomenon for decades, call it “positive assortative mating” – which really just means that we marry people like ourselves. When it comes to love, we don’t scan a very broad horizon. People may have an interest in people who are different from themselves but they don’t marry them. They’re looking for confirmation, for comfort.
- All personalization software does the same thing: make our lives easier by reducing overwhelming choice. And software is doing it the same way that our brain does, by searching for matches. This is immensely efficient: It means that the brain can take shortcuts because it is working with what it already knows, not having to start from scratch. When we find what we like, part of our pleasure is the joy of recognition. But the flip side of that satisfaction is that we are rejecting a lot along the way.
- We like ourselves, not least because we are known and familiar to ourselves. So we like people similar to us – or that we just imagine might have some attributes in common with us. They feel familiar too, and safe. And those feelings of familiarity and security make us like ourselves more because we aren’t anxious. We belong. Our self-esteem rises. We feel happy. Human beings want to feel good about themselves and to feel safe, and being surrounded by familiarity and similarity satisfies those needs very efficiently. The problem with this is that everything outside that warm, safe circle is our blind spot.
- Bias is pervasive among all of us, whether we think we’re biased or not.
- The argument for diversity is that if you bring together lots of different kinds of people, with a wide range of education and experience, they can identify more solutions, see more alternatives to problems, than any single person or homogenous group ever could. Groups have the potential, in other words, to be smarter than individuals; that’s the case put forward so compellingly by James Surowiecki in his book, The Wisdom of Crowds. But the problem is that, as our biases keep informing whom we hire and promote, we weed out that diversity and are left with skyscrapers full of people pretty much the same.
- But while it’s true that all of us now have access to more information than ever before in history, for the most part we don’t use it. Just like newspapers, we read the blogs that we agree with – but there we encounter a virtually infinite echo chamber, as 85 percent of blogs link to other blogs with the same political inclination.
- Our blindness grows out of the small, daily decisions that we make, which embed us more snugly inside our affirming thoughts and values. And what’s most frightening about this process is that as we see less and less, we feel more comfort and greater certainty. We think we see more – even as the landscape shrinks.
- Indeed, there seems to be some evidence not only that all love is based on illusion—but that love positively requires illusion in order to endure. When you love someone, he or she may even start to adapt to your illusion of him or her. So there is a kind of virtuous circle: you think better of your beloved who starts to live up to your illusions and so you love him or her more. It sounds a little like a fairy tale, but kissing frogs may make them act like princes or princesses. It is indeed a kind of magic, illusions transforming reality. We don’t have to love people for who they are but for who we think they are, or need them to be. This is something everyone does: overlook the flaws, discount the disappointments, focus on what works. Our love for each other allows us, even compels us, to see the best in each other.
- One of the many downsides of living in communities in which we are always surrounded by people like ourselves is that we experience very little conflict. That means we don’t develop the tools we need to manage conflict and we lack confidence in our ability to do so. We persuade ourselves that the absence of conflict is the same as happiness, but that trade-off leaves us strangely powerless.
- Because it takes less brain power to believe than to doubt, we are, when tired or distracted, gullible. Because we are all biased, and biases are quick and effortless, exhaustion makes us favor the information we know and are comfortable with. We’re too tired to do the heavier lifting of examining new or contradictory information, so we fall back on our biases, the opinions and the people we already trust.
- People stay silent at work—bury their heads in the sand—because they don’t want to provoke conflict by being, or being labeled, troublemakers. They may not like the status quo but, in their silence, they maintain it, believing (but also ensuring) the status quo can’t be shifted.
- Hierarchies, and the system of behaviors that they require, proliferate in nature and in man-made organizations. For humans, there is a clear evolutionary advantage in hierarchies: a disciplined group can achieve far more than a tumultuous and chaotic crowd. Within the group, acceptance of the differing roles and status of each member ensures internal harmony, while disobedience engenders conflict and friction. The disciplined, peaceful organization is better able to defend itself and advance its interests than is a confused, contentious group that agrees on nothing. The traditional argument in favor of hierarchies and obedience has been that of the social contract: It is worth sacrificing some degree of individuality in order to ensure the safety and privileges achieved only by a group. When the individual is working alone, conscience is brought into play. But when working within a hierarchy, authority replaces individual conscience. This is inevitable, because otherwise the hierarchy just doesn’t work: too many consciences and the advantage of being in a group disappears. Conscience, it seems, doesn’t scale.
- Human beings hate being left out. We conform because to do so seems to give our life meaning. This is so fundamental a part of our evolutionary makeup that it is strong enough to make us give the wrong answers to questions, as in Asch’s line experiments, and strong enough to make us disregard the moral lessons we’ve absorbed since childhood. The carrot of belonging and the stick of exclusion are powerful enough to blind us to the consequences of our actions.
- Independence, it seems, comes at a high cost.
- The larger the number of people who witness an emergency, the fewer who will intervene. The bystander effect demonstrates the tremendous tension between our social selves and our individual selves. Left on our own, we mostly do the right thing. But in a group, our moral selves and our social selves come into conflict, which is painful. Our fear of embarrassment is the tip of the iceberg that is the ancient fear of exclusion, and it turns out to be astonishingly potent. We are more likely to intervene when we are the sole witness; once there are other witnesses, we become anxious about doing the right thing (whatever that is), about being seen and being judged by the group.
- It is so human and so common for innovation to fail not through lack of ideas but through lack of courage. Business leaders always claim that innovation is what they want but they’re often paralyzed into inaction by hoping and assuming that someone else, somewhere, will take the risk.
- The greatest evil always requires large numbers of participants who contribute by their failure to intervene.
- Technology can maintain relationships but it won’t build them. Conference calls, with teams of executives huddled around speakerphones, fail to convey personality, mood, and nuance. You may start to develop rapport with the person who speaks most—or take an instant dislike to him or her. But you’ll never know why. Nor will you perceive the silent critic scowling a thousand miles away. Videoconferencing distracts all its participants who spend too much time worrying about their hair and whether they’re looking fat, uncomfortable at seeing themselves on screen. The nervous small talk about weather—it’s snowing there? It’s hot and sunny here—betrays anxiety about the vast differences that the technology attempts to mask. We delude ourselves that because so many words are exchanged—e-mail, notes, and reports—somehow a great deal of communication must have taken place. But that requires, in the first instance, that the words be read, that they be understood, and that the recipient know enough to read with discernment and empathy. Relationships—real, face-to-face relationships—change our behavior.
- The division of labor isn’t designed to keep corporations blind but that is often its effect. The people who manufacture cars aren’t the people who repair them or service them. That means they don’t see the problems inherent in their design unless a special effort is made to show it to them. Software engineers who write code aren’t the same as the ones who fix bugs, who also aren’t the customer-service representatives you call when the program crashes your machine. Companies are now organized—often for good reasons—in ways that can facilitate departments becoming structurally blind to one another.
- We want money for a very good reason: it makes us feel better. Money does motivate us and it does make us feel better. That’s why companies pay overtime and bonuses. It may not, in and of itself, make us absolutely happy—but, just like cigarettes and chocolate, our wants are not confined to what’s good for us. The pleasure of money is often short-lived, of course. Because there are always newer, bigger, flashier, sweeter products to consume, the things we buy with money never satisfy as fully as they promise. Psychologists call this the hedonic treadmill: the more we consume, the more we want. But we stay on the treadmill, hooked on the pleasures that, at least initially, make us feel so good.
- Motivation may work in ways similar to cognitive load. Just as there is a hard limit to how much we can focus on at one moment, perhaps we can be motivated by only one perspective at a time. When we care about people, we care less about money, and when we care about money, we care less about people. Our moral capacity may be limited in just the same way that our cognitive capacity is.
- Money exacerbates and often rewards all the other drivers of willful blindness: our preference for the familiar, our love for individuals and for big ideas, a love of busyness and our dislike of conflict and change, the human instinct to obey and conform, and our skill at displacing and diffusing responsibility. All these operate and collaborate with varying intensities at different moments in our life. The common denominator is that they all make us protect our sense of self-worth, reducing dissonance and conferring a sense of security, however illusory. In some ways, they all act like money: making us feel good at first, with consequences we don’t see. We wouldn’t be so blind if our blindness didn’t deliver the benefit of comfort and ease.
- Once you are in a leadership position, no one will ever give you the inner circle you need. You have to go out and find it.
- We make ourselves powerless when we choose not to know. But we give ourselves hope when we insist on looking. The very fact that willful blindness is willed, that it is a product of a rich mix of experience, knowledge, thinking, neurons, and neuroses, is what gives us the capacity to change it. We can learn to see better, not just because our brain changes but because we do. As all wisdom does, seeing starts with simple questions: What could I know, should I know, that I don’t know? Just what am I missing here?
Automated checking is not a new concept. Gojko Adzic, however, provides us a way to make better integration of it in our software development processes. In his book titled “Specification by Example”, he talks about executable specifications that double as a living documentation. These are examples which continuously exercise business rules, they help teams collaborate, and, along with software code, they’re supposed to be the source of truth for understanding how our applications work. He builds a strong case about the benefits of writing specifications by example by presenting case studies and testimonials of teams who have actually used it in their projects, and I think that it is a great way of moving forward, of baking quality in.
Some favorite takeaways from the book:
- Tests are specifications; specifications are tests.
- “If I cannot have the documentation in an automated fashion, I don’t trust it. It’s not exercised.” -Tim Andersen
- Beginners think that there is no documentation in agile, which is not true. It’s about choosing the types of documentation that are useful. There is still documentation in an agile process, and that’s not a two-feet-high pile of paper, but something lighter, bound to the real code. When you ask, “does your system have this feature?” you don’t have a Word document that claims that something is done; you have something executable that proves that the system really does what you want. That’s real documentation.
- Fred Brooks quote: In The Mythical Man-Month 4 he wrote, “The hardest single part of building a software system is deciding precisely what to build.” Albert Einstein himself said that “the formulation of a problem is often more essential than its solution.”
- We don’t really want to bother with estimating stories. If you start estimating stories, with Fibonacci numbers for example, you soon realize that anything eight or higher is too big to deliver in an iteration, so we’ll make it one, two, three, and five. Then you go to the next level and say five is really big. Now that everything is one, two, and three, they’re now really the same thing. We can just break that down into stories of that size and forget about that part of estimating, and then just measure the cycle time to when it is actually delivered.
- Sometimes people still struggle with explaining what the value of a given feature would be (even when asking them for an example). As a further step, I ask them to give an example and say what they would need to do differently (work around) if the system would not provide this feature. Usually this helps them then to express the value of a given feature.
- QA doesn’t write [acceptance] tests for developers; they work together. The QA person owns the specification, which is expressed through the test plan, and continues to own that until we ship the feature. Developers write the feature files [specifications] with the QA involved to advise what should be covered. QA finds the holes in the feature files, points out things that are not covered, and also produces test scripts for manual testing.
- If we don’t have enough information to design good test cases, we definitely don’t have enough information to build the system.
- Postponing automation is just a local optimization. You might get through the stories quicker from the initial development perspective, but they’ll come back for fixing down the road. David Evans often illustrates this with an analogy of a city bus: A bus can go a lot faster if it doesn’t have to stop to pick up passengers, but it isn’t really doing its job then.
- Workflow and session rules can often be checked only against the user interface layer. But that doesn’t mean that the only option to automate those checks is to launch a browser. Instead of automating the specifications through a browser, several teams developing web applications saved a lot of time and effort going right below the skin of the application—to the HTTP layer.
- Automating executable specifications forces developers to experience what it’s like to use their own system, because they have to use the interfaces designed for clients. If executable specifications are hard to automate, this means that the client APIs aren’t easy to use, which means it’s time to start simplifying the APIs.
- Automation itself isn’t a goal. It’s a tool to exercise the business processes.
- Effective delivery with short iterations or in constant flow requires removing as many expected obstacles as possible so that unexpected issues can be addressed. Adam Geras puts this more eloquently: “Quality is about being prepared for the usual so you have time to tackle the unusual.” Living documentation simply makes common problems go away.
- Find the most annoying thing and fix it, then something else will pop up, and after that something else will pop up. Eventually, if you keep doing this, you will create a stable system that will be really useful.
We want performant, scalable, and quality software. We wish to build and test applications that our customers profess their love to and share to their friends.
- We have nonexistent to little unit, performance, API, and integration tests
- The organization do not closely monitor feature usage statistics
- Some of us do not exactly feel the pains our customers face
- We don’t have notifications for outdated dependencies, messy migration scripts, among other failures
- Some are not curious about understanding how the apps they test and own actually work
- We have not implemented continuous build tools
- It is a pain to setup local versions of our applications, even to our own programmers
- We do not write checks alongside development, we lack executable specifications
- Some still think that testing and development happen in silos
- It is difficult to get support for useful infrastructure, as well as recognition for good work
- Many are comfortable with the status quo
It seems that we usually have our expectations mismatched with our practices. We’re frequently eager to show off our projects but are in many instances less diligent in taking measures about baking quality in, and therefore we fail more often than not. What we need are short feedback loops, continuous monitoring, and improved developer productivity, ownership, and happiness. The difficult thing is, it all starts with better communication and culture.
I’ve stumbled over Alister Scott‘s WatirMelon blog some years back, probably looking for an answer to a particular question about automation, and found it to be a site worth following. There he talks about flaky tests, raising bugs you don’t know how to reproduce, junior QA professional development, the craziest bug he’s ever seen, writing code, and the classic minesweeper game. He was part of the Watir project in the past, but is now an excellence wrangler over at Automattic (which takes care of WordPress). He has also written an intriguing book, titled “Pride and Paradev“, which talks about several of the contradictions that we have over in the field of software testing. In a nutshell, it explains why there are no best practices, only practices that work well under a certain context.
Here are a number of takeaways from the book:
- A paradev is anyone on a software team that doesn’t just do programming.
- Agile software development is all about delivering business value sooner. That’s why we work in short iterations, seek regular business feedback, are accountable for our work and change course before it’s too hard.
- Agile software development is all about breaking things down.
- Agile software development is all about communication and flexibility. You must be extremely flexible to work well on an agile team. You can’t be hung up about your role’s title. Constantly delivering business value means doing what is needed, and a team of people with diverse skills thrives as they constantly adapt to get things done. Most importantly flexibility means variety which is fun!
- Delivering software everyday is easy. Delivering working software everyday is hard. The only way an agile team can deliver working software daily is to have a solid suite of automated tests that tells us it’s still working. The only way to have reliable, up-to-date automated tests is to develop them alongside your software application and run them against every build.
- You’re testing software day in and day out, so it makes sense to have an idea about the internals of how that software works. That requires a deep technical understanding of the application. The better your understanding of the application is, the better the bugs you raise will be.
- Hiring testers with technical skills over having a testing mindset is a common mistake. A tester who primarily spends his/her time writing automated tests will spend more time getting his/her own code working instead of testing the functionality that your customers will use.
- What technical skills a tester lacks can be made up for with intelligence and curiosity. Even if a tester has no deep underlying knowledge of a system, they can still be very effective at finding bugs through skilled exploratory and story testing. Often non technical testers have better shoshin: a lack of preconceptions, when testing a system. A technical tester may take technical limitations into consideration but a non technical can be better at questioning why things are they way they are and rejecting technical complacency. Often non-technical testers will have a better understanding of the subject matter and be able to communicate with business representatives more effectively about issues.
- You can be very effective as a non-technical tester, but it’s harder work and you’ll need to develop strong collaboration skills with the development team to provide support and guidance for more technical tasks such as automated testing and test data discovery or creation.
- Whilst you think you may determine the quality of the system, it’s actually the development team as a whole that does that. Programmers are the ones who write the good/poor quality code. Whilst you can provide information and suggestions about problems: the business can and should overrule you: it’s their product for their business that you’re building: you can’t always get what you consider to be important as business decisions often trump technical ones.
- A tester should never be measured on how many bugs they have raised. Doing so encourages testers to game the system by raising insignificant bugs and splitting bugs which is a waste of everyone’s time. And this further widens the tester vs programmer divide. Once a tester realizes their job isn’t to record bugs but instead deliver bug free stories: they will be a lot more comfortable not raising and tracking bugs. The only true measurement of the quality of testing performed is bugs missed, which aren’t recorded anyway.
- Everything in life is contextual. What is okay in one context, makes no sense in another. I can swear to my mates, but never my Mum. Realizing the value of context will get you a long way.
- Probably the best thing I have ever learned in life is that no matter what life throws at you, no matter what people do to you or how they treat you, the only thing you can truly control is your response.
I’ve mentioned Jame Bach and Michael Bolton’s ‘Rapid Software Testing’ ebook before. I am citing their resource once more today because they’re worth revisiting again and again, for software testers. Many of the things I’ve come to believe in about software testing are here, explained well in interesting lists, charts, and descriptions. Such are the things that junior software testers need to fully understand, as well as the stuff that seniors should thoroughly teach.
Quoting some lines from the slides:
- All good testers think for themselves. We look at things differently than everyone else so that we can find problems no one else will find.
- In testing, a lot of the methodology or how-tos are tacit (unspoken). To learn to test you must experience testing and struggle to solve testing problems.
- Asking questions is a fundamental testing skill.
- Any “expert” can be wrong, and “expert advice” is always wrong in some context.
- The first question about quality is always “whose opinions matter?” If someone who doesn’t matter thinks your product is terrible, you don’t necessarily change anything. So, an important bug is something about a product that really bugs someone important. One implication of this is that, if we see something that we think is a bug and we’re overruled, we don’t matter.
- It’s not your job to decide if something is a bug. You do need to form a justified belief that it might be a threat to product value in the opinion of someone who matters, and you must be able to say why you think so.
- In exploratory testing, the first oracle to trigger is usually a personal feeling. Then you move from that to something more explicit and defensible, because testing is social. We can’t just go with our gut and leave it at that, because we need to convince other people that it’s really a bug.
- Find problems that matter, rather than whether the product merely satisfies all relevant standards. Instead of pass vs fail, think problem vs no problem.
- How do you think like a tester? Think like a scientist, think like a detective. Learn to love solving mysteries.