Testing a website on different versions of IE

So, no matter how much you argue that it’s an ancient, irrelevant browser; there’s no way you can wriggle out of having to test your web app against IE6 on WinXP. But… trying to find a machine with it lying around might be difficult. Magnanimous Microsoft have made testing your web app on different IE/Windows combinations less tedious than it could be: combine Virtual PC with a collection of pre-built images and you’re on your way. Here are the details…

First, you’ll need to install Virtual PC:

  • Download the latest version of Virtual PC from here if you’re running Windows 7
  • Download Virtual PC 2007 from here if you’re running Windows XP/Vista

Next, you’ll need to download as many of the following combinations of Windows/IE as you want from here.

The Windows/IE combinations available are:

  • IE6 / XP SP3
  • IE7 / XP SP3
  • IE7 / Vista SP1
  • IE7 / Vista SP2
  • IE7 / Vista SP3
  • IE8 / XP SP3
  • IE8 / Vista SP1
  • IE8 / Vista SP2
  • IE8 / Vista SP3

Download the images you need, start them, get your testing done before the VM runs out of time (they’re time limited) and then get back to doing something less painful!

Enjoy your multi-IE-version testing. Rather you than me ;)

Test Case Interdependency

One of the most common ways of structuring a series of test cases is to make one test case dependent on the outcome of another. For example, Test Case ‘A’ verifies the functionality surrounding the ability to create an account. Test Case ‘B’ verifies functionality surrounding account deletion, but instead of stating that the required data is and account in a particular state, it states that the account generated by test case ‘A’ should be the one to test for deletion. The mistake cascades through the test cycle: in execution of the test suite, if test case ‘A’ fails then test case ‘B’ cannot be executed and so it is marked as ‘failed’.

This test case interdependency causes problems for automation. It’s also a bad thing to do in general. Why?

In the above example, when it comes down to it, test case ‘B’ is not dependent on test case ‘A’ at all. If ‘B’ is testing deletion, it should test deletion. Deletion is dependent on an account, not necessarily a specific one (i.e. the one generated by test case ‘A’). OK, the account to test deletion against may need to be in a specific state (e.g. not already marked for deletion, etc…) but that’s not the same as dictating a specific account number.

As well as being, er, “philosophically” wrong, interdependency of test cases leads to testers incorrectly failing tests. Marking test case ‘B’ as failed just because test case ‘A’ did produces incorrect data in the test report. Why? Marking a test as failed when it hasn’t been executed is wrong, no matter what the reason is. The tester executing test case ‘B’ should have picked one of the (possibly) large number of valid accounts to use instead of being limited to test case ‘A’s account. That way, the ‘delete’ functionality can be tested even if the ‘create’ functionality is broken.

How is this a problem for automation? Well, an automated test should be just that: an automatic version of a manual test. Hard-wiring data into automated tests is common (and sold as a ‘feature’ of many packages), but makes the tests very fragile. If the data doesn’t exist (due to other tests failing), some tests won’t be able to run even though there may be plenty of valid data to use!

An easy fix is to make a slight modification to your tests: change them to be dependent on data in a particular state rather than specific data. Subtle difference with a large impact on test case management and execution. You’ll still be testing the same functionality, but the tests are much less interdependent. You’ll be able to execute all your tests (not just a subset) and your automated tests will be much more reliable and maintainable.

Link to ISEB Testing study documents

I did the ISEB exam a while ago. I didn’t revise for the exam, I just turned up and did it. It took a few minutes and I was done. I don’t have a high opinion of the exam – the ISEB subject matter is largely irrelevant to testing in the real world. Unfortunately, many employers put it on the list of requirements when hiring so it’s a good thing to have… if only to be on the shortlist of candidates.

Anyway, if you’re going for the exam, here’s a site that may be of interest:

http://isebtesting.blogspot.com/

It has links to documents you can use to prepare. I don’t know how long it’ll be around for…

Data Conversion Testing

(NB: I’m writing this about half a day after having *5* wisdom teeth out – bear with me…)

Most projects involve some kind of data conversion from a legacy system. Testing data conversion it is boring as hell and very easy. Here’s how to do it.

Fundamentally, data conversion testing is no different from any other types of testing. You should have some sort of requirement spec, and as normal you should write your tests off that. The main difference between the way data conversion testing is done and the way functional testing is done is that for the former you should (for the most part) use SQL queries, for the latter you should (for the most part) use the GUI. Therefore the testers that will be writing/performing the data conversion testing need to know SQL. You can get by without knowing the syntax for the INSERT, UPDATE etc queries; but knowledge of the SELECT query and everything that can be used with it is pretty much essential. A fine memory-jogger is the SQL Pocket Guide from O’Reilly. The tester will also need an even higher-than-normal boredom threshold level than is usually needed for functional testing. Data conversion testing is *really, really* boring.

So, now on to the different levels of data conversion testing. There are basically 2 levels at which the testing is done: technical testing, and business “warm-and-fuzzy” testing. The technical testing will verify the conversion against the specs; the business testing will give business representatives a warm and fuzzy feeling inside – ie: confidence that when they lay their old system to rest, all their precious data has been copied across correctly into the new system.

Technical Testing
The starting point of technical testing is a Data Conversion Specification. It should detail the various processes that will be used too convert the data. It should include statements like: “Copy all [specific object type to convert] records from the [legacy system] with the following criteria: (1) only [field1] = 1 or 2 or 3 but not 4, (2)”, and “for every [insert converted object] create a new record in the [something] table with the fields populated with the following data: [field1] = [value1], [field2] = [value2], [field3] = [value3]“.

Like any other testing, you should begin by establishing test traceability. At least one test should be written against each statement like the above ones. By doing this, you can ensure that the tests will cover all data that is to be converted.

Next: how to write the tests. Just like any other testing, there are actions and there are expected results when writing data conversion tests. The action is usually something like “Execute the following query and record the result”, which is followed by the query that is to be executed to test the condition. The Expected Result should contain something like: “Zero rows are returned.” You could also include a phrase such as: “Any rows that are returned are [specific object] IDs that are missing the expected [object property]” – defect diagnosis is made quite a bit easier.

So… the queries to be executed. There are may ways that you could write queries to test that a particular record has been correctly converted. I’ll concentrate on the 2. They are the most commonly used, and you get the biggest bang for your buck with them. They are:

  • Row Counts
  • Identify Objects with Missing Data

Row Counts
These are easy. In their simplest format, they go something like this:

select count(*) from [a table]

These can be performed on the source and target tables to compare the number of records. If the conversion is a straight conversion, the above query will do (well, for checking numbers of rows anyway). If only records with particular parameters are being converted, the way to check that the number of rows in the target table is correct is to run the following queries:

Run against Source Table

select count(*) from [source table]
where
[field1] = [some condition] AND
[field2] = [some other condition]

Run against Target Table

select count(*) from [target table]

That will give you the number of rows in the subset of the source table that are to be converted, and the total number of rows in the target table. The test passes if the numbers match.

Identify Objects with Missing Data
These queries are more complex than row counts, but they provide a fair bit more value. Their purpose is to identify parent objects whose child objects that should have been converted are missing. In the example spec above, we had the following:
“for every [insert converted object] create a new record in the [something] table with the fields populated with the following data: [field1] = [value1], [field2] = [value2], [field3] = [value3]“

To test that each parent object has their child object, write the SQL query in the following stages:

1) Write a query that will pull the foreign key that goes back to the parent table out of the child objects table, eg:

select parent_id from childObjectTable
where
[field1] = [value1] AND
[field2] = [value2] AND
[field3] = [value3]

This will give you the all of the correctly converted child objects.

2) Write a query against the parent table that pulls out all of the parent_id’s that should have a child object in the childObjectTable, eg:

select id from parentTable
where
[fieldX] = [some value]

3) Now combine the above 2 queries so that the new query only displays the parent_id’s that don’t exist in the first query, ie:

select id from parentTable
where
[fieldX] = [some value] and
id not in (
select parent_id from childObjectTable
where
[field1] = [value1] AND
[field2] = [value2] AND
[field3] = [value3]
)

The end result of this is to list all of the parent id’s that are missing a correctly converted/generated child object in the childObjectTable.

The cool thing about this style of query is that if it comes back with 0 rows in the result set, the test has passed. Little to no paperwork for anyone involved. If rows *were* returned in the result set, you’ve identified the bad rows and can immediately investigate them, or give the list to the data conversion developer for them to sort out. No fuss.

Now of course you’ll have more than just the above 2 styles of queries, but you’ll probably find that you can write the vast majority of the tests in that style.

Business Testing
As part of the development process, business representatives should have written a checklist of things that they’d like to check. Rarely are they in more detail than the technical testing. I’ve usually been handed a sheet of paper with 10 bullet points on saying things like: “Show that the account for customer ABC has got the same balance on both systems”. An interesting thing to keep your eye out for is statements like: “Show that we can still run batch job XYZ against converted data”. This is *not* data conversion testing, it is functional testing being done against converted data. Although this needs to be tested, it should be done as part of functional testing, not data conversion testing.

Anyway, the business tests, once identified can be done either by using SQL queries or by running GUI tests. I’d recommend using the GUI. Business are much happier that way and will have a lot more confidence in the new system and its new set of data. So, write out a test in the style of a functional test that includes navigation through the system etc… that will show the set of data in both the legacy and the new system. The business representative will know what they’re looking for in the old system, and by following the actions in the test, you can demonstrate that the data they are interested in has been correctly converted (or not!).