| James's profileJames McCaffreyBlogLists | Help |
|
November 23 Declaring and Using an Object of Type InterfaceOne particular scenario with C# interfaces is very confusing for beginners. Suppose you see code like this:
ICar mySedan = new Sedan(2008);
What exactly is going on here? We have an object named mySedan, a constructor Sedan(), and an Interface ICar. You would expect the code to look like this:
Sedan mySedan = new Sedan(2008);
because an interface is a contract, or a template, which does not have any implementation. For example, consider these "normal" interface and class definitions:
// version #1 - "normal"
public class Sedan : ICar { public int year; public Sedan(int y) { this.year = y; } public void display() // <- note this signature { Console.WriteLine("The year of the sedan is " + this.year); } } public interface ICar
{ void display(); } Here we have an interface ICar which says in essence, "When you define a class derived from me, you must code a display() method." The Sedan class derives from ICar as you'd expect and implements the display() method. Now to call this version you could use:
Sedan mySedan = new Sedan(2008);
mySedan.display(); // displays "The year of the sedan is 2008" OK, so far so good. But because the Sedan class derives from ICar, you could also use this version:
ICar mySedan = new Sedan(2008);
mySedan.display(); // also displays "The year of the sedan is 2008" which is the code I started this discussion with and explains one scenario where you can declare an object which has an Interface type. But now comes the tricky part. There is a scenario where you must declare an object which has an Interface type. Suppose you implement the Sedan class slightly differently:
// version #2: explicit Interface method definition
public class Sedan : ICar { public int year; public Sedan(int y) { this.year = y; } void ICar.display() // <- note difference { Console.WriteLine("The year of the sedan is " + this.year); } } public interface ICar
{ void display(); } Here I use "an explicit interface implementation". Now to call this version, if you try the normal calling technique:
Sedan mySedan = new Sedan(2008);
mySedan.display(); // will not compile your code will not compile. In this scenario you must declare the object as an Inteface type like this:
ICar mySedan = new Sedan(2008);
mySedan.display(); // displays "The year of the sedan is 2008" To summarize, if you see an object declared as an interface type such as ISomething, then a.) it might be a case where you can change the type to a specific type, or b.) it might be a case of explicit interface implementation.
November 14 Pair-Wise TestingPair-wise testing is a simple and fundamental testing concept that has been around for a long tikme, and which is best explained by example. Suppose you are testing some application which has two drop-down controls and a radio-button list. The first drop-down control can have a value of either "a", or "b". The second-drop-down can have a value of "c", "d", "e", or "f". The radio-button can be either "g", "h", or "i". Exhaustively testing this situation is easily possible. The 2 * 4 * 3 = 24 test inputs would be:
a, c, g
a, c, g a, c, i a, d, g . . . b, f, i But what if you had say, 8 controls, each of which could be one of 5 values. You'd have 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 = 390,625 combinations to test. The basic idea of pair-wise testing is to reduce the number of combinations in some way. This is accomplished a generating test sets which capture all possible pairs of inputs. In the example above, there are a total of 26 distinct pairs of inputs: {a,c} {a,d} (a,e} {a,f} {b,c} {b,d} (b,e} {b,f} {c,g} {c,h} {c,i} {d,g} {d,h} {d,i} {e,g} {e,h} {e,i} {f,g} {f,h} {f,i} {a,g} {a,h} {a,i}.
The theory is that these will generate good test case inputs. So consider the test input set {b, d, h}. This test set covers 3 of the 26 total possible pairs: {b,d} {b,h} {d,h}. Now suppose I add another test set of {b, c, h}. This second test set covers pairs {b,c} {b,h} {c,h}. Notice the {b,h} pair is covered by both test sets so at this point I have 5 of the 26 total pairs covered.
So, just how do you generate a list of test sets which capture all possible pairs? It turns out that this is a fascinating, NP-complete (translation, really, really hard) problem. The PICT (Pairwise Independent Combinatorial Testing) tool (see http://msdn.microsoft.com/en-us/library/cc150619.aspx) is a really nice command-line tool that can generate pair-wise combinations.
I wrote my own version of PICT for fun, using C#, and it worked out pretty well but generated about 15% more test sets than PICT. I'm experimenting with a genetic algorithm approach too.
November 09 Windows Server 2008 Multi-Boot ConfigurationsIn a software testing scenario, it is common to have computers that can boot into several different operating systems so that you can test on different OS platforms without requiring multiple machines, each with a single OS. In general, you should always install multiple operating systems in order from oldest to newest. For example, on many machines I use, I have two physical hard drives. I install Windows XP first onto a first partition on the first hard drive, then I install Windows Server 2003 onto a second partition of the first drive and then I install Windows Server 2008 onto the second physical drive. To manage the boot sequence data for Windows XP and Windows Server 2003, I manually edit the boot.ini text file located on the first physical hard drive. But Windows Vista, Windows Server 2008, and above, use a different multi-boot management scheme. Boot information is stored into a boot configuration database (BCD). To edit this data you must use the bcdeedit.exe command line tool. To view existing configuration data, type the command:
> bcdedit.exe /enum ACTIVE
or simply bcdedit.exe without any arguments. To get general help, type bcdedit.ee /? and to get specific help with an argument, type:
> bcdedit.exe /? delete
for example to get detailed help about how to delete an unused configuration entry. I recently reinstalled Windows Server 2008 on a machine (because the secondary hard drive holding that OS failed). This created a duplicate "Windows Server 2008" entry in the boot menu displayed when the machine is first powered on. So I first viewed all entries to see their associated BCD IDs, and then deleted the duplicate entry along the lines of:
>bcdedit.exe /delete {12345678-abcd-12ab-a1b2-1234567890ab}
Then to get the legacy Windows OSes (XP and Server 2003) to boot as default rather than Server 2008, I entered the command:
> bcdedit.exe /default {ntldr}
All in all, it doesn't take too long to get used to the new Boot Configuration Database and its command-line editor.
November 01 Socket-Based Web Application TestingThis past week I was thinking about Web application testing. A business unit asked me to implement a collaborative tool. I decided to use a PHP framework. I got the system up and running but when I turned the system over to the IT group in charge they balked saying, in essence, they didn't know PHP. There's a whole interesting sub-story here about the don't-use-anything-new mentality of many IT departments vs. the constantly-innovate mentality of many software development departments. However, I was mostly struck by the lack of understanding of the basic nature of Web applications. This in turn started me thinking about HTTP request-response testing Web applications. The idea here is to programmatically send an HTTP request to the Web app under test, fetch the HTTP response, and analyze the response for an expected value of some sort. Now there are several ways to send HTTP requests. A low level approach is to write code which uses TCP/IP sockets and send raw HTTP text. A higher level approach, and one which is far more common, is to use wrapper code which encapsulates much of the low-level details you have to deal with explicitly when using a socket-based approach. For example, socket-based code looks something like:
string message = // set up message
string host = // URL to Web app IPHostEntry iphe = Dns.Resolve(host); IPAddress[] addList = iphe.AddressList; EndPoint ep = new IPEndPoint(addList[0], 80); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(ep); string header = "POST " + " HTTP/1.1\r\n";
header += "Host: " + host + "\r\n"; header += "Content-Type: text/whatever; charset=utf-8\r\n"; header += "Content-Length: " + message.Length.ToString() + "\r\n"; header += "Connection: close\r\n"; string sendAsString = header + message;
byte[] sendAsBytes = Encoding.ASCII.GetBytes(sendAsString); int numBytesSent = socket.Send(sendAsBytes, sendAsBytes.Length, SocketFlags.None); // set up buffered loop to fetch HTTP response stream // analyze response So why even consider a relatively complex socket-based approach to HTTP request-response testing when there are easier techniques? There are two main reasons. First, the socket-based approach allows you to do things you can't do using some higher level approaches, such as send corrupted HTTP messages (to analyze security issues for example). Second, the socket-based approach adds to your fundamental understanding of exactly what goes on with Web applications. If the IT guys I worked with last week had a mindset of constantly embracing new ways of doing things, they'd likely be far more knowledgeable about Web technology and probably would not have balked at using PHP.
|
|
|