Object Test Bench – II: A User’s Manual…

Hi folks…

This blog was due a long time back… I haven’t been able to get down to it so far because of multiple reasons, first of which is that I suffer from a chronic case of ELDS: Extreme Laziness Disorder Syndrome :-). Second, I have just moved into a new team – Visual Studio for Devices. I have been busy doing the transition work and oh boy, there is still a lot to be done!

Third reason, a genuine one, is that I have been wondering about the format of this blog. Since this is a User’s Manual, obviously there needs to be lot of pictures and illustrations. But too many of them will make the blog too big to sit through! At this point I came across the WinkTM. This is a fantastic tool for creating animated illustrations. All SWF tutorials in this blog are created using that tool, except the sections with the enhanced datatips. Satish – great job and thanks!

In this blog, I will take you through the various features of OTB. The
 image in each section points to an animated tutorial for that section. Please note this blog is not the official OTB documentation. The official document is here.


Getting started:

OTB can be accessed in the VS IDE as follows:

1.    Class View (CV): From the context menu of a supported CodeType, you can create instances of the CodeType as well as invoke its static methods.

2.    Class Designer (CD): From the context menu of a shape for a supported CodeType, you can create its instance and invoke its static methods.

3.    OTB Tool Window: Once an instance of a CodeType is created, a shape representing the instance is available on the tool window. From the context menu of the shape, you can invoke methods on the object. You can also remove the object from test bench.

The above context menus are populated dynamically with the constructors, static and instance methods for each CodeType/object. The methods inherited by the CodeType from its parent hierarchy appear in the Inherited Methods group. Also only methods/constructors that conform to certain restrictions appear on the context menus. Here is an example.


Create Instance:

Right click on a CodeType in the CV or CD to obtain the context menu. For each CodeType recognized by OTB, a Create Instance submenu will be available on the context menu, if the CodeType has at least one constructor recognized by OTB.

On clicking on one of the menu items, OTB will display a dialog like the following:

Click to view the full size image...

You can then enter the values of each parameter that you want to pass to the method in the parameter entry grid. For primitive types, you can type in arbitrary values (e.g. for a string, you can enter any arbitrary string in the value cell). For both primitive and non-primitive types, the dropdown in the value cell lists the available values. The available values consist of the following:

·         Default values, if any. (E.g. default values for Boolean are false and true. For an enum type, the default values are all the defined enumerations)

·         At most 5 most recently used values for primitive types.

·         All objects in the test bench whose types are the same as the parameter type or a subtype of the parameter type.

Click to view the full size image...

Once you are done entering all the parameters, press OK and barring any failures/exceptions, you should have an object on the test bench.

A CodeType is not recognized by OTB if it doesn’t meet these conditions. E.g. OTB v1 does not recognize generic types. You will not be able to use OTB features on unrecognized CodeTypes. Although that you can create instances of most classes and structs, you cannot create instances of abstract classes, arrays, delegates, interfaces, enums etc.

A constructor is recognized by OTB subject to these conditions. OTB will not display or invoke constructors that it cannot recognize.


Invoke Static Methods:

The CV/CD context menu for a recognized CodeType will also include the Invoke Static Method submenu. This menu lists all the static methods of the CodeType, subject to these restrictions. The static methods inherited from the parent hierarchy are grouped under Inherited Methods submenu. CodeTypes are recognized subject to the same conditions described in the Create Instance section above.

Clicking on one of the items in the Invoke Static Method menu will throw up a dialog box similar to the Create Instance dialog box, except that the Name field will not be present. After entering the parameters and press OK and OTB will invoke the method for you and return the result to you as described in the Method Call Result section below.


Invoke Instance Methods:

Right clicking on an object on the test bench will bring up the Invoke Method submenu. This menu lists all the methods that can be invoked on the object, subject to these restrictions. The methods inherited from the parent class are listed under the Inherited Methods menu. For J# and VB, this list of methods includes the static methods of the CodeType also. For C# the methods listed are the instance methods only.

The test bench can contain objects are actually references to arrays, interfaces, abstract classes, enums and delegates apart from classes and structs. You can invoke methods on any of these.

To invoke one of the instance methods, click on the respective item in the Invoke Method menu and follow the procedure described in the Invoke Static Method section.


Method Call Result:

Assuming there are no errors/failures after you invoke a method (static or instance), there are two cases. First, if the return type of the method is void, a dialog will be shown informing you that the method call succeeded. Optionally you can choose to reinvoke the method with different parameters by clicking Retry.

If the return type of the method is not void, following dialog box will be thrown up:

Click to view the full size image...

At this point you can choose to save the return value onto the test bench. You can also choose to reinvoke this method with different parameters by clicking Retry. On clicking Retry, you will be presented with the method invoke dialog as described in the Invoke Method sections above.


Inspect/Modify Objects on the Test Bench:

Once an object is added to the test bench, hovering over it will bring up the Enhanced Datatip.

Click to view the full size image...

The enhanced datatip allows you to navigate the entire object – all fields, properties, entire parent hierarchy right up to System.Object by just hovering. Apart from navigating the entire object, you can also change/edit the read/write fields & properties.

The enhanced datatips also give you access to the customized display of objects using the Debugger Visualizers.


Step Through Code in Break Mode:

This is useful when you have written a utility function that has especially convoluted algorithm (E.g. generating CRC for a given block of data)… Now once you have finished implementing the algorithm in a GenerateCRC32 function, you would like to perform some unit tests. You then typically invoke this method using OTB as described above.

Now what happens when you see that the method call result is not what you expected? The first instinct is to place a breakpoint and step through the code right? But wait, don’t F5 yet!

Instead place a breakpoint at the relevant point inside GenerateCRC32 and then invoke this using OTB. Once you have entered the required parameters and pressed OK in the Invoke Method dialog, OTB asks the debugger to evaluate GenerateCRC32. Note that we are still in the design mode when the debugger starts evaluating GenerateCRC32 under the hood.

Now when this under–the–hood–execution hits the breakpoint, the debugger enters break mode and you will see that the function evaluation has been suspended at the breakpoint. Now you are *completely* in break mode – you can use the autos/locals windows; do step–in/step–over/step–out; use (quick)watch windows and all other IDE features that you normally use while stepping through. It is as if you had pressed F5/F10/F11 initially and entered directly into GenerateCRC32. Note that for the usual F5/F10/F11 process you have to write a driver code for you utility method, step through the driver code and then finally reach and step through GenerateCRC32. Essentially, you are doing F1/F10/F11 on any arbitrary function without having to write driver code.

Once you are done stepping through GenerateCRC32 you can simply hit a F5 and the debugger will reenter the design mode (Note: design mode not run mode), wait for the function evaluation to complete, return the method’s return value to OTB. Finally OTB will display the result as described in the Method Call Result section above.

I hereby dub thee Design–Mode–Debugging! :-)


Immediate Window Interaction:

One way to look at OTB is that it is an intelligent GUI over the Immediate Window (IW). Whatever you do using OTB you can also do using the IW (albeit you don’t have the features described in the above sections). So if you declare an integer using “int i = 0;” in the IW, the integer “i” will appear in the test bench. Subsequently if you change the value of “i” or even delete “i”, these operations will get reflected on the test bench.

What’s more, every operation performed by OTB is logged into the command window as statements in the language of the project you are working on. You can save this sequence of statements and later on execute them one by one in the IW to recreate your session.

But there are certain cases in which you would want to use the IW because OTB doesn’t provide a way out. Remember that I had earlier mentioned earlier that using Create Instance UI you cannot create instances of abstract classes, arrays, delegates, interfaces, enums etc.? Well using IW you can get around most of this limitation. You get instances of arrays, delegates and enums on the test bench by simply executing their constructor statements in the IW. E.g. “string[] stringArray = new string[] { "1", "2" };”. For abstract classes and interfaces you can get their null instances on the test bench by simply executing their declaration statements. E.g. “IAppDomainSetup appDomainSetup;”.

Now you might ask: Using the IW, can I trick OTB into adding instances of instantiated generic classes? Unfortunately no! An object of any CodeType that OTB doesn’t recognize will not be added to the test bench, although it is possible to create such objects and use them from the IW. What this means that if you evaluate “List<int> intList = new List<int>();”, the object “intList” will be created and you can invoke methods on it from the IW. But “intList” will not be added to the test bench and OTB cannot operate on “intList”.


OTB Sessions and Out–of–Date Projects:

An important scenario is when you have created a lot of objects on the test bench and then for some reason you need to make a minor change to the code before you can create the next object or invoke the next method. What happens then?

Technically, once you have recompiled the code, the new assembly generated and classes in it are completely different from the ones in the previous built even though you may not have made any code changes. Extending this, once you have objects on the test bench and then you make some changes to the code, the objects aren’t really valid. They are from classes that have been discarded. Basically you cannot invoke methods on the new classes/objects using objects from the discarded classes.

So in the scenario above, once there are changes in the project that require a rebuild, OTB will prevent you from performing the next operation without a rebuild. You can choose to rebuild the project in which case the test bench will be cleared. Alternatively you can continue to inspect and modify the objects on the test bench using the enhanced datatips.


Handling Errors/Failures/Unhandled–Exceptions:

In case of failures that occur while OTB is performing some operation, OTB will abort the current operation and report a diagnostic message about the failure. These failures include build breaks, unhandled–exceptions and other general failures. In case of unhandled–exceptions the diagnostic message will be the exception’s text message. Once presented with the error, you can take the corrective measures and retry the operation.

 

Whew! That pretty much describes what you can do using OTB. Next blog in this series will illustrate some real life use–cases. See you then…

(To be continued…)