I am filled with solutions

Weekly essays on testability, testing and being a tester.

  • Programming in 2009 isn't much different than R&D in 1898 it seems

    The Australian Physicist, Sir Richard Threllfall (1861-1932) remarked in 1898 - 

    "Though, no doubt, a great deal can be done with inferior appliances where great economy of money and none of time is an object, the writer has long felt very strongly that English physical laboratory practice has gone too far in the direction of starving the workshop, and he does not wish, even indirectly, to give any countenance to such a mistaken policy. Physical research is too difficult in itself, and students' time is too valuable for it to be remunerative to work with insufficient appliances."

    This could just as well have read like this today.

    "Though, no doubt, a great deal can be done with inferior appliances where great economy of money and none of time is an object, the writer has long felt very strongly that programming practice has gone too far in the direction of starving the workshop, and he does not wish, even indirectly, to give any countenance to such a mistaken policy. Research and development is too difficult in itself, and engineers' time is too valuable for it to be remunerative to work with insufficient tools."

  • Creating URL configurable Visual Studio Web Tests

    Creating URL configurable Visual Studio Web Tests

    I recently joined a project with a lot of web based APIs. This is pretty typical and Visual Studio 2008 let me start creating load tests literally within hours of being accepted onto the project. I quickly created a library of about one hundred web tests. Everything was going well until the day I realized I needed to point all my tests to a new server. The prospect of changing one hundred URLs on a regular basis made me stop and think about how to do it better. As I have developed these tests, I have come up with a set of best practices for VSTS load tests for my team. I have also create a method for adding on-the-fly URI and other data to the visual studio load tests without converting them to code.

    Since my team has several test environments, I need to change my tests to be able to point to different systems easily. With this system I can change the URL in an arbitrary number of test as fast as I can edit one XML file and hit “F5” to run the tests. I also am no longer troubled by a bug where I had to remove and re-add web tests to load tests if I changed the URL.

    You can use this system for any test URL. If your tests have a lot of different base URLs, your settings file will need an entry for each of them.

    Best practices for web tests that will be use for load testing

    ·         Keep your functional tests separate from the load tests. Fancy functional tests are cool, but they are hard to debug in load scenarios. K.I.S.S. principle applies to load tests.

    ·         Avoid converting web tests to code. Keeping them in the simple “native” test format keeps management easy.

    ·         Use the plug in architecture whenever you need to customize web tests.

    ·         Use a global settings file for settings that need to change for different environments.

    ·         Load tests should not perform complicated scenarios. If possible they should contain just one call to the application under test.

    ·         In order to use this URL configuration as is all the tests need to hit the exact same URL. E.G. http://myserver/app/api.apsx? However, you can easily add as many URLs as you like to the config file.

     

    Creating your settings file

    Since your web tests are effectively running as a plug-in or DLL to the test system you can’t easily use an app.config file like you might for your own executables. This isn’t much of a problem; it’s really easy in .Net to create a configuration class. If you are following along at home, fire up your Visual Studio and create a new project. Pick test project. Then right click the solution and add a class library project named “WebTestSettings”. Rename class1 to be “WebTestSettings” as well. Mark the class [Serializable] and add the parameters you require as public properties.  You will also need to add internal Save and Load methods. Here is my class that provides a SQL connection string to a web plug-in and sets the test API URI. For this application save is optional. I don’t use it in this project. I briefly hooked up some throw away code to write out the first config file.

    Settings Class

        [Serializable]

        public class WebTestSettings

        {

            public string SqlConnectionString { get; set; }

            public string ApiURI { get; set; }

     

     

            internal void SaveConfig(string ConfigFilePath)

            {

                StreamWriter writer = new StreamWriter(ConfigFilePath);

                XmlSerializer serializer = new XmlSerializer(typeof(WebTestSettings));

                serializer.Serialize(writer, this);

                writer.Close();

            }

     

            internal void ReadConfig(string ConfigFilePath)

            {

     

                StreamReader reader = new StreamReader(ConfigFilePath);

                XmlSerializer serializer = new XmlSerializer(typeof(WebTestSettings));

                WebTestSettings readSettings = (WebTestSettings)serializer.Deserialize(reader);

                this.SqlConnectionString = readSettings.SqlConnectionString;

                this.ApiURI = readSettings.ApiURI;

                reader.Close();

            }

        }

    Now you will need to create your settings file. For this code my settings file came out like this. You can use the SaveConfig method to write out your config file. I didn’t use it for anything else, but I kept it in the class in class for completeness.

    Settings.xml

    <?xml version="1.0" encoding="utf-8"?>

    <WebTestSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="WebTestSettings.xsd">

      <SqlConnectionString>Data Source=(local);Integrated Security=true;Initial Catalog=MyDatabase</SqlConnectionString>

      <ApiURI>http://myServer/application/api</ApiURI>

    </WebTestSettings>

    WebTestPlugin to pass parameters into your tests

    Add a reference to Microsoft.VisualStudio.QualityTools.WebTestFramework to the project. Create a new class called “SettingsPlugIn”. Add  using Microsoft.VisualStudio.TestTools.WebTesting;”. Derive your new class from WebTestPlugin.

    We are going to hard-code the name of the settings file into this class. (In theory this violates best practices, but since the web tests run in a particular environment, we can get away with this.) Next, override the PreWebTest function of the base class. Add your new parameters and set them from the settings file.

    SettingsPlugin class

        public class SettingsPlugIn : WebTestPlugin

        {

            private WebTestSettings settings = new WebTestSettings();

            private const string settingsFile = "WebTestSettings.xml";

     

            public override void PreWebTest(object sender, PreWebTestEventArgs e)

            {

                settings.ReadConfig(settingsFile);

                e.WebTest.Context.Add("SqlConnectionString", settings.SqlConnectionString);

                e.WebTest.Context.Add("ApiURI", settings.ApiURI);

                base.PreWebTest(sender, e);

            }

        }

    Getting your web tests to use the new settings file

    There are several steps you have to complete to get the settings file where the web tests can locate them.

    Add the WebTestSettings project as a reference to the test project

    Right click references and find it on the project tab. Hit F6 to build everything.

    Add the settings file to the test project

    Save your config file to the file name you hard-coded into the plug-in class, "WebTestSettings.xml" in this case. Add the file to the TestProject you created earlier. (You can optionally add an XSD file to quell Visual Studio warnings. I used the XSD.EXE tool to create my XSD.) Set the “Copy to output directory” property on the xml file to “Copy if newer”.

    Adding the config to a web test

    Create a new web test to access your application. You can just make a recording as usual.

    Add the settings file as a deployment item to the test

    This is a little harder than it should be. Hopefully the next version of VSTS will make this easier.

    1.    One the menu select Test->Windows->TestView

    2.    Highlight your web test in the list. (You might need the column chooser to tell web tests apart from other items if you have a lot of tests.)

    3.    In Properties click “Deployment Items” and an ellipsis […] will appear next to “String[] Array”. Click it.

    4.    In the Dialog Box type in the name of the settings file. “WebTestSettings.xml”

    Add the plug in and change the url to use the settings file value

    1.    On the web test right click the base node and select “Add web test plug-in…”. Select the SettingsPlugIn.

    2.    Click the URL and in the properties window set it to {{ApiURI}}

     

    Now when you run the test the results will start off showing the URL as {{ApiURI}} and then change it to the URL as soon as the plug-in runs and the name is resolved. Now you can point to a new system to test for all your tests in one quick change to the settings XML file.

    Caveats

    ·         Visual Studio seems to have some issues with the plug-ins. If you have to change the plug in code, you will need to delete all the OBJ, BIN and TESTRESULTS directories in the solution, otherwise the new code won’t get picked up.

    ·         Visual Studio seems to cache web tests. If you update a web test that is already part of a load test, you will need to remove and re-add the web test when you change the URL. Once you get this plug-in running you can just update the XML file in the root of the webtest directory instead.

    ·         This example doesn’t show you the plug-in I use to get additional data from a database, which is what the connection string is for. Built in data sources are nice, but when you need to share tests with other team members, you might not want to share datasources.

     

     

     

  • Consider replacing strings with Enums in resource references.

    Consider replacing strings with Enums in resource references.

    I see code like this all the time in test and XNA and I really dislike it.

     

     

                MyCustomResourceClass resources = new MyCustomResourceClass();

                MyImageClass currentImage = resources["Image 1.jpg"];

     

     

    I dislike because it’s nearly impossible to tell where the list of valid resources lives. You don’t want to put a comment on every reference to the resources class. Some /// documentations in the resources class might help, but you probably want to keep it generic.

     

    I prefer a pattern that looks like this.

     

                //List of resources in the MyImages.XML file from the resources Directory.

                enum AvailableImages

                {

                    Image1,

                    Image2,

                    Image3

                }

              

               MyImageClass nextImage = resources[AvailableImages.Image2];

     

    You do incur overhead maintaining the enum, but it makes your code much clearer and promotes run time errors to compile time errors. Remember you can add descriptions to the enums if you have to do something like map to filenames with spaces in them. Then the resources class can have some intelligent code for looking up the file names.

  • The right and wrong way to create unique data for tests.

    I have noticed some code in various places that creates some conditions for mysterious test failures. You know the kind; “It works on my machine but will never seem to run in the lab.”

    In our tests its sometimes desirable to have a unique identifier. There are a lot of possible ways to create this data, but only one is sure fire. Use GUIDS.

    Let’s say we are creating ID strings for whatever reason. 

    The right way: Use GUIDs.

    string uniqueString = Guid.NewGuid().ToString("N"); //N removes punctuation to keep the length to 32.

    Guids are designed to be unique. Don’t worry about collisions. Don’t worry about running out. If you can afford the 32 characters, use a GUID.

    Hint: Guids are hexadecimal numbers. If you need to “compress” one you can get a 32 digit GUID into 13 digits by converting it to base64.

     

    The appealing wrong way: Combine the time with a random number.

                Random random = new Random();

                string uniqueString = DateTime.Now.ToString() + random.Next(1000); //Random doesn't mean "no duplicates!". You are prone to the Birthday Paradox.

     

    You can fiddle with the time output to get this down to about 20 characters.  If your tests run in 1/100th of a second or concurrent runs you will run into problems due to the birthday paradox.

     

    The really wrong ways: Time only, Random Only.

            string uniqeName = "MyTests" + DateTime.Now.ToString();//If you run this too fast or concurrently you will get duplicates. Easy to do!

    Or

            private static Random random = new Random();

            String uniqueName = random.Next().ToString(CultureInfo.InvariantCulture); //Random doesn't mean "no duplicates!". You are prone to the Birthday Paradox.

     

  • Working with Permuations and Combinations

    Something tests end up doing a lot of is working with permutations and combinations. For those of you who didn't have the benefit of a good statistics class in college (or some gambling experience after) doing the math can be a hassle. Generating all the possibilities can also be a bit of a puzzle (it's like counting in a mixed base number system sometimes).

    I have found myself needing to generate lists of permutations (list1 x list2 x list3 in all combinations) and combinations (all the ways you can get dealt 5 cards from a 52 card deck) once in a while. While doing API testing I realized it would be handy to code up some generic generators that I could re-use anytime I wanted.

    http://www.codeplex.com/permutationTools has the libraries I created for this purpose.

    The math to calculate the number of permutations and combinations is built in. The logic to step through the lists and get a minimal set, or a full permutation list is encapsulate inside with an easy "foreach" handle.

    Lately I have been using these to automatically generate thousands of test cases for methods I want to give a solid workout to. This kind of testing can be daunting to create by hand. Just a handful of parameters can put you into the thousands of test cases. You can create a central method that accepts various input and drive it at run time with the tools, or you can turn the process inside out and create a program to write tests.

    I do the later because it fits into my test harness and reporting system better. If I run 10,000 tests and one permutation fails I want the report to say 99.99% pass. If you run all the permutations as one test you get 100% fail. That's not really an indication of the product quality.

    You have to be careful not to write impenetrable test code when using techniques like this. Make sure your BVT and Basic acceptance test cases are hand written and clear before you generate 10,000 cases that rely on tricky logic.

     

  • What constitutes a unit test?

    When I speak of unit tests, sometimes there is a slight communication breakdown. Just becuase a developer wrote a test in the unit test harness does not a unit test make. This post does a good job of drawing a line in the sand.
  • Please stop re-inventing the wheel.

    Please stop re-inventing the wheel.

    There are a lot of software wheels that get re-invented all the time. Re-inventing is a time consuming waste that many projects can cut. In almost all cases it’s much better to do some due diligence and use an off the shelf component where you can. Invest your time, passion and expertise in your actual product.

    Save your energy for your real innovations

    Engineers are smart. Sometimes we get cocky and think because we know how to build the best X on the web, we also know better about everything else too. Don’t fall into this trap. It’s very unlikely a genius web developer can really create a better database than off the shelf. There are too many good ideas begging to be programmed. Don’t waste time on something that’s outside your core innovation. The world needs customer focused applications that work well with people. Don’t waste your time creating the ten thousandth backend widget you could have gotten for free on the internet.

    Existing protocols are good

    Nothing makes me crazier than software that implements a broken version of a standard protocol. You can spend time designing a brand new protocol, but if you are doing something that is well known on the ‘net you should try hard to work with existing protocols. Existing protocols have some miles on them and are usually good compromises for everything they do. Designing and testing new protocols is just quicksand for most projects. If you can’t say that the new protocol is the heart of what’s cool about your product, then don’t make a new protocol.

    Get your design patterns off the shelf

    Most software project fall into some pretty well known patterns. Console applications, three tier web applications, client-server applications and peer to peer applications are very common patterns. If your product falls into any well known pattern, follow the best practices for your pattern. Innovate where you are really on the cutting edge and try to use cookies cutters wherever else you can.

     

  • Writing code for today and tommorow

    Writing code for today and tomorrow

    Any developer working at a pace that will allow them to stay employed creates bugs. Testers get excited about a lot of different bugs. Testers should be lobbying for fixes that will have the biggest impact on the software. Teams don’t always agree on what those things are. Think about how the bugs you are fixing (or not) will impact you down the road.

    Old code never dies

    Computer code feels like it has a short lifetime. However this just isn’t the case. The code you worked on five or ten years ago may be old news in your mind. However, most production code written that long ago is still alive in one form or another. It’s extremely expensive to re-write from scratch. Working code is really hard to throw away. Remember a ton of COBOL programs that had to be updated for the year 2000. Computer code has a way of living a long life.

    Maintainability

    Maintainability is more than just a development concern. If your team uses visual studio you can get a maintainability index (from 0 to 100) for all the code in your project. You should try it sometime. If your code isn’t averaging at least 80 chances are you have some issues at a low level. Keeping these numbers high pays dividends for the lifetime of the code. Don’t be pedantic about those numbers. Some code is actually better in a “complex” form. 10% of your code can have a free pass to go as low as 40 on the Visual Studio maintainability index. Keeping your code maintainable will pay off for years and years, maybe even decades.

    Sustained Engineering

    The original author usually has the luxury of handing off code they wrote after the release. There are some good business reasons for this. However, code that’s hard to fix and update will come back to haunt you. I have seen projects drug into the mud when they constantly had to deal with customer “escalations” because no one but the original authors could maintain the code. The first release was out the door in short order, but the cost to the company and the project lasted for years and years.

    The cost of repaving the road

    You can’t anticipate which parts of your project are going to have to be overhauled in three years. Computers will get faster, but users will demand more out of them. A lot of applications continue to scale just by migrating to better infrastructure. However, at some point software projects need to be overhauled or re-written. Make sure you fix your issues that cause your software to be tightly coupled. That way in three years you can yank out the one bad part and put in a new fancy one. If your project is still tightly coupled, it won’t be able to be updated and it will die a premature death.

    Customers aren’t the only customers

    When you evaluate which bugs to fix, you should think about the customers. You just have to remember that the person sitting behind the desk using your application isn’t the only customer. Think carefully before you choose to fix a bug that only a small number of users will ever see over improving maintainability or leaving backend hacks in place

    You have a responsibility to your first customer, the company who writes your paycheck. You have a responsibility to the “customers” who will maintain your work when you move on. Finally you have a responsibility to customers who will be using some version of your product years from now. Make sure all your customers are feeling the love.

     

     

  • Planning Software projects Part 1

    Planning Software projects Part 1

    Good planning is critical to delivering software. Anyone who has shipped a product knows that the plans we start with rarely survive the entire release process intact. Too many of the plans we start with are useless by the time we ship our software. Ideally our plans would serve us better through the entire process. Here are some lessons about planning I have learned that should help you spend you planning time better.

    Good business starts with a vision

    A clear vision will do more to help you ship software that delights your customers than any other planning you do. This is very important so I will repeat it. You must have a clear vision and communicate it clearly to your team. Teams who can’t do this have no way to live up to their potential. Your vision must unify your marketing goals with your engineering goals and it must be realistic and achievable.

    Good products flow from a vision. You can have the most technically sophisticated components known to man, but without a unifying vision they are doomed. This part of your planning is really, really important. If you neglect it, I promise you will cause suffering and randomization in your team about midway through the cycle!

    Define one or two primary pillars and two or three secondary pillars.

    The pillars of your product should be a rough guide to where you will spend your time downstream. One approach to software pillars is to imagine each attribute your software can have is a dial from one to ten. You can set each dial at a number and then arrive at the probably amount of time it will take to achieve your vision. The trick is that you have a limited budget. Most projects can only survive having one or two pillars be set to “10” and two or three more set above “5”.

    How can you decide what pillars are important? Talk to your customers. Find out what they really want. They will want everything, of course. Find a way to make them stack rank what they want, and proceed from there.

    Some sample pillars you might work with:

    ·         Feature rich

    ·         Usable

    ·         Robust

    ·         Scalable

    ·         Maintainable

    ·         Testable

    ·         Technically advanced

    ·         Performing

    ·         First to market

    A lot of software projects pay lip service to pillars, but fail to really nail down the vision for each one. If you want to create a product that scores a 10 on each one of those scales, you will have to pay the price in time, talent and your resale cost is going to be high to compensate.

    The best software projects start from a vision that is specific about what pillars are important, which ones are secondary and which ones are going to be “left for the next version.”

    Some pillars are diametrically opposed to others. If you want to score a ten out of ten on “first to market” you can pretty much forget about scoring very high in the other pillars.

    Make sure before you start to design features that you know what you want the software to achieve in the market. Make this vision clear and public for the team. Don’t use weasel words in your vision statement. When conflicting priorities present themselves, a clear vision will make for smooth sailing. For example, if a feature is causing the ship date to slip, a clear vision will allow you to quickly decide if you should slip or cut the feature.

    Finally it’s important to say what pillars aren’t part of this release. If performance isn’t a primary consideration, say so in the vision. Otherwise you will find your team spending a lot of time trying to performance tune a product that shouldn’t be tuned in this release. You can’t have everything in one release. So prioritize and learn to let go of everything else.

    When you vision is clear and clearly communicated, your team is set up to succeed.

    If your feature crew are struggling ask if the support systems are in place. Can they get builds and run automated tests at will? If not, no amount of planning is going to help them when they discover something nobody thought of. Is it clear how important the feature is to the project, how well it must work and how fast? If not, you will have resource contention issues that will drain valuable resources from your team.

    No plan survives contact with the enemy

    I worked on a team that had a pretty good process for creating software. They sketched out some pillars, whipped up some prototypes, tried out the combination and then did some mid course corrections. However, parts of the process could have been optimized. The problem was that the plan on paper didn’t match the plan in reality. So anytime you wanted to change the process you got stuck with the fact that no one was following the “real” plan in the first place.

    If your actual process doesn’t follow the script it’s likely the script is flawed. This is probably a very healthy occurrence. Try to capitalize on the evolutionary nature of your organization. It will adapt to overcome challenges. Don’t make a rigid insistence on outdated plans one of those challenges.

  • Planning software projects Part 2

    Planning software projects Part 2

    Plan how you will work

    Plan your infrastructure first

    In order for your team to be successful you will need to have some processes running smoothly. Builds, setup, automated testing, bug reporting and status are vital to the success of your project.

    Plan out how you will achieve all the work goals. Set up prototypes and get the system running before you work on real product code. A product that has a shell of setup and a completely automated system that builds, installs, tests and reports has a strong leg up on competition that leaves these things till later in the cycle.

    Setup in particular is not an end game feature! Setup is the first impression your customer gets of the product. Every feature needs a way to get shipped and installed. Plan how this will work up front and make sure the system is functional before you start on feature coding.

    Plan to have the development team help with the tools and processes. They are really good at these tasks. Leaving them out is asking for trouble. If test “owns” setup you can bet they will work their butts off to make it fly, but they will be fighting development all the way down the road. Make sure the entire team owns the technologies and processes you use to ship your products. Plan it into your release. It really makes a big difference in the end game.

    Architect your product

    Before the features are designed your product should have an overall plan. How the components fit together, where the abstractions points are and the construction phases are all critical. You should have a plan to achieve your pillars. If you want the most feature rich product in the world, you better plan (and execute on) to have a solid platform for all the features to plug into.

    You might build a house around really killer windows the point at a great view. That’s fine, but you still have to have a foundation. Those awesome windows won’t do you much good on a mud hut you built at the last minute because you spend all your time making the windows.

    Plan to make your product loosely coupled at all code levels. Plan to make your product testable. Plan to make your product maintainable. Plan for every pillar you can think of. Write the plan down and give it to the team. Go through all the pillars and carefully plan how you will achieve (or ignore) each one that applies to your product.

    This kind of planning is something that needs to be vetted by senior programmers. Business managers can tell you what to build, but get the engineers involved in the how. Make sure everyone is on the same page and agrees it can be done before you start. Otherwise you will live out a Dilbert cartoon.

    Don’t “rat hole” on the features

    We typically spend an enormous amount of time planning our features to the nth degree. This is a big waste of time. Plan to iterate on your features. If you have a strong vision and planned your work well, then iterating on features will be cost effective.

    When features aren’t coming together we often make the mistake of thinking we didn’t plan them well enough. The truth is that more often the failure to plan was at a different level. An experienced feature crew can plan and execute on a feature at warp speed if the pillars and infrastructure are solid.

     

  • Hyper-v export to off machine share trick.

    Today I wanted to export a hyper-v machine to a share on a computer with more disk space. However I got this error: 'General access denied error' (0x80070005). I didn't have enough disk space to just make it locally and transfer it over. I really should get another disk for that system, but not today.

    I quickly realized the problem. Hyper-v doesn't try to export with my permissions. It uses the permissions the service started under. I figured out two work arounds. Both are probably security issues, so tread with caution and common sense. Either method could allow unauthorized users and programs to write to the host you do the steps on. The second method at least contains this to one directory. Don't trust any executables that show up in that share. You should probably also remove the permissions when your task is done.

    First, and untested, change the service accounts that hyper-v runs under to a domain account that has permissions to the share in question. The restart hyper-v. That will probably work. However the amount of damage that can happen if something goes wrong is unpredictable.

    Second, add the MACHINE itself to the share permissions on the desination. You can do this the exact same way you would add a user (Click the advanced sharing button in Vista). However, in the permissions dialog box you have to click "Object Types" and check "Computers" in order to be able to see the computers.

     

    From the Object Types screen click "Ok" then enter the name of the computer you want to give the permissions to. Then check "full control".

    Once you hit OK on all the layers the machine itself will have permissions to write to the share.

  • Book Review: The Human Factor: Revolutionizing the Way People Live with Technology by Kim Vicente

    Book Review: The Human Factor: Revolutionizing the Way People Live with Technology by Kim Vicente

    This book is required reading for everyone who develops technology for people to use. Vicente uses the phrase “human-tech” to describe technology that is a good fit between people and the machines they use.

    One story describes how a toy wheel glued to an airplane control completely eliminated a deadly “pilot error” that crashed planes and killed pilots during World War II. Another describes how a mismatch of technology and human needs led to a small town being poisoned and the Chernobyl disaster.

    The book explains clearly and precisely how considering the human factor appropriately can make living with technology easier and improve everyone’s quality of life. The lessons in the book move from concrete objects like pens and phones up through a series of steps all the way to policies and politics. If hospitals treated near misses the same way the FAA does today, nearly 100,000 people a year could be saved and many more would not be harmed or maimed by medical mistakes.

    The lessons in the book are especially important for those of us in the software industry. Our products are rarely “life or death” but the chance to improve the fit with the way people actually behave and work are very important. The later chapters contain valuable information on how to design our processes to improve our chances of success in the marketplace and increase satisfaction with the products we make.

    Testers in particular should take these lessons to heart. When we are being advocates for the customer, we have to understand how people really use technology. The things that make technology easier and harder to use are outlined. We have so many programs and gadgets, but so few of them fit really well with our daily life and the uses we want from them. The ones that do are run-away hits in the market. If you wonder how to replicate that, then you should study this book.

    What if regular household batteries were shaped so there was no way to put them in backwards? How much simpler would it be to deal with them. However, the batteries we have are now the industry standard. It’s basically too late to change. What a terrible missed opportunity. Don’t let your product miss out on simple but effective ways to work better with people. Read this book and think hard about your customers.

  • Working Smart in Test - a simple approach to personal workflow

    Working Smart in Test

    A situation came up this week with two different testers in my team. They both asked about the approach they were taking to a problem. Both of them were doing a lot of testing and they were trying to decide on a depth-first or breadth first approach.

    In the end they ended up taking different approaches to similar problems. However, both approaches minimized randomization.

    Minimize context switches

    A typical test cycle on a feature involves a lot of thing. At some point you generate test cases, run them and report results. In most cases you need to figure out the approach that will make you most productive. Designing one test case, running it, dissecting the results and then reporting that one result before moving on to the next one isn’t an ideal way to tackle testing. You will be switching applications and thought processes very frequently. These context switches are very expensive in terms of easy things like mouse miles and clicks. They are also very disruptive to your brains natural process. You are preventing yourself from developing a rhythm or identifying the big picture.

    Group similar tasks

    Henry Ford figured out that an assembly line boosts productivity for cars. A lot of the tasks we do in test can be assembly lined. For example, you need to create test cases in the test case repository.

    You could take a depth first approach, where you complete an entire test case before you move on to the next. In most cases you can do better. For example, you might use a tool to input all the test cases titles in one shot. I have even used some hacked together scripts to generate test case titles for predicable parts of a project. Being able to upload hundreds of test case titles in a few seconds is really rewarding.

    The important thing is to identify task groupings and try to get all the tasks at a certain level done as a group.

    Do the easy stuff first

    Once you start running the tests you might find out that some of the test cases aren’t easy to run or verify. You can easily get hung up trying to debug, diagnose or improve these trouble children. Don’t do it. You will be paying a time tax to context switch. If something breaks the pattern, kick it on to another pile and keep moving.

    It’s much better to finish 80% of your test cases on Monday and then spend the rest of the week diving deep into the 20% that gave you trouble. Your boss has a much better idea of the health of the software. Your developers have bugs you already found to work on. Best of all, if you run out of time, you did a significant fraction of the work.

    Bug investigations fall in the same bucket. It might be best to log a lot of bugs that don’t have all the information you ultimately want in the bug. It’s much better to log 20 bugs a day that are missing details than log one bug a day with all the possible details. Be sure to note in the bug that you plan to come back later and provide details, if that’s your plan. During a test pass you want to put emphasis on finding bugs. When the test pass is over you can shift to fixing bugs.

    Whenever you run into problems, ask if you can safely postpone a deep dive in order to knock out the easy stuff. Many times you can do just that and it will save you a ton of time.

    Another example of this is when you have people helping you out. Say you just hired a tester to help out in the area you are an expert. You could make them do everything you do and let them call or talk to you anytime they have issues. It’s a lot more productive to have them do everything they can do by themselves and make a list of all the questions or problems they have and deal with them all at once. This same trick works with your boss when he or she “pitches in” in your area.

    Circle back for the hard stuff at the end.

    Of course you don’t want to neglect the tricky problems. You do need to address them. Just don’t let them distract you and cause a lot of context switching through the entire endeavor. In fact, you will probably benefit from having a rhythm with the deep dives at the end as well.

    Do it better

    Everyone in test gets distracted by trivia at one time or another. If you pay attention to what you are doing, you can catch yourself “rat-holing” and get back on track. Things get hard. We get behind schedule. Sometimes “pulling it in” is just a matter of re-arranging the order of our work.

     

  • Wordle

    Ok, this is just plain old fun. Here is a "map" of my last 3 blog posts. Click for full size.

     

  • Practical debugging; Apply some science to the problem

    Practical debugging; Apply some science to the problem

    Untested software has bugs. As we test software we find a lot of different kind of bugs. We want to identify the root causes for as many bugs as we can. Finding root causes can be fiendishly difficult and time consuming. Using a systematic, scientific approach can help you with the hard problems.

    Say you have a program that used to work, but now it crashes. You look into it and realize it’s been broken for quite some time and fell through the holes in your testing. Now you have several related check ins and dozens of others that have a remote possibility to be the culprit.

    Stop poking at problems with that stick

    When we find problems in software we often have a good idea what the problem might be. We do some informal checking and poking around. Most of the time, this behavior pays off. Our experience and intuition are valuable and we get to the heart of the problem without a lot of thrashing. The problem comes when this approach fails us. All too often we keep blindly poking with a stick and end up thrashing around and not finding the answer.

    A good rule of thumb is to switch to a more rigorous approach when your guesswork has failed three or more times. In our example you might guess it was the latest check-in and back that out. You find out that is no good and the program still crashes. You check the dependencies and they don’t reveal anything. Next you run the test on some other machines and find it’s a universal problem. At this point you should make a solid plan for when to stop guessing and when to switch to a more controlled approach.

    Use the scientific approach

    At its heart science is testing your beliefs. When you were guessing about the source of the problem you were doing this in a relaxed way. Now you realize that nothing obvious is wrong and you will need to do some deeper technical work. You need to use the scientific method. For software testing there are really just three key things to keep in mind.

    Control the variables

    You need to make sure you are changing things one at a time while you run your tests. You might get the program to work after you re-installed the operating system on the host, changed some code and rebuilt the database. What you won’t know is what fixed the problem and if it’s gone for good. When you switch to a rigorous method, you have to be careful and control the variables one at a time. It’s easy to fall into the trap of changing lots of stuff and trying again. You might get the program working again quicker, but you lose too much valuable diagnostic data. In lab environments this is especially tempting. You just need the environment “up” to complete your work. The problem is you don’t know if it was a trivial error you will never see again, or if you just put a tarp over a deep pit.

    You should be taking notes on the variables and how you change them at this point. You don’t have to exhaustively note every little thing, but you should be able to back out any changes you make. In code this means having a checkpoint. In an installation this may mean a snapshot image. Maybe it’s just a list of values you change in the database. Just be sure you can unwind the stack if you have too.

    Create a hypothesis

    Once you have control of the variables you need to guess again about what is wrong. But you need to do it in a controlled way. State your idea in a way that you can prove wrong. It’s a good idea to write your hypothesis down.

    In the example of the crashing program, we might hypothesize anything from a corrupt pointer assignment to something outrageous like “it won’t work on Tuesdays when the moon is full.” The most important thing is that your hypothesis is narrow enough to be tested. Often it’s a really good idea to make a list of things you don’t think are wrong and test them first. A good example might be “The file was corrupted at install time.” We don’t really think this is causing the program to crash, since we have several versions of the installer and it’s unlikely they would all be corrupt. However its possible and until we clear it as a culprit it could be masking other problems.

    Try to prove it wrong

    Once you have a hypothesis do an experiment. You need to design your experiment so that it will prove your hypothesis wrong. You also need to design it so that you change the fewest variables possible to prove your hypothesis wrong.

    In our example we could diff the file with the one on the build server. If they are identical, we know that the corruption hypothesis was wrong. Scratch it off the list and move on to another one.

    Rinse and repeat.

    Jump start the car before you take the engine apart

    The problem with this approach is the sheer number of hypothesis there are. Defining them all narrowly and then designing an experiment to test them will be very time consuming. You need to use an approach that weights getting results quickly. An analogy is a car that won’t start. Nearly any part in the car could be bad. Based on your history with the car you might have some guesses. While you are going through all the possibilities you might as well try to jump start the car. It’s easy to do, and only take a few minutes. If the car starts, wonderful, you are done. If not, you quickly ruled out a very common reason for cars not starting (dead battery).

    Rank your hypotheses to get most coverage

    When you start to think about your hypotheses rank them by how hard they are to do and how much information they give you. Start with the easiest experiments that give you the most information.  Every test you do gives you data. All of that data can help you decide what tests you should focus on.

    In the example of the crashing program, you might have one hypothesis that a particular line of code is at fault and another that the network connection on the host machine is at fault. An experienced network engineer can rule out 99% of network problems with a few simple tests. If that’s quicker and easier than tweaking the line of code, start there. On the other hand, you may have the code open in an editor and building and installing may be trivial. In that case you can test your “line of bad code” hypothesis much easier than a network problem.

    Stick with the science

    It’s tempting to go back to poking your problems with a stick. You rule out a few major problems and you start exploring at random again. This is rarely productive. If you find yourself changing lots of variables at once, you are probably wasting time. If you are stuck for more experiments, then you can explore some to get more data. But if you have plenty of possible culprits, keep working through the list. It’s just like running any other set of test cases.

     

     

     

More Posts Next page »

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker