CSharpening

  • A couple IDE tips

    1. Set Breakpoint using the Find Combo Box

    You can use the breakpoint dialog to set a breakpoint. But if you feel that’s too slow for you, use the Find Combo Box which is on the toolbar and next to Find in Files.

    clip_image002

    In the Find Combo Box, type in the function name, e.g. Main as indicated in the above figure, and then hit F9. You will notice a breakpoint is set on function Main.

    Overloaded methods are supported as well. In the following figure, we have two overloaded methods M. Type in the function name M in the Find Combo Box and then hit F9, we can see breakpoint is set on both of the methods M.

    clip_image004

    2. A little bit more fun with the Find Combo Box

    You can open project files from the Find Combo Box. There are multiple ways to do that. For example, if you want to open file foo.cs:

    · Type in the filename foo.cs and press CTRL+SHIFT+G

    · Enter “>open foo.cs”

    · Enter “>of foo.cs”

    3. Threads Window

    When you are doing multithread debugging on multiple CPU systems, it can be problematic especially when single stepping. When this happens, you might want to freeze some threads so they don’t execute. You can do this by opening the threads window and right click on the thread and select Freeze from the context menu. Be careful as you might mess up you application.

  • An effective test tool - CodeInjector

    CodeInjector

     

    CodeInjector is a tool that validates various language service features on arbitrary code. The tool is extremely easy to set up and it uses idle cycles on your machine to do testing. It is a fault injection tool that inserts, removes, and replaces tokens in C# files, checks for errors during injection and also builds and checks for internal compiler errors. It has the ability to trap all exceptions in VS and Command Line Compiler csc. The tool is fully automated and has fault tolerant capabilities. Whenever the tool finds an issue (i.e. a product crash), it saves a minidump with heap, and it resumes running the tests after the dump is saved.

     

    We have been finding a good amount of bugs using this tool. It helps to stabilize our product faster and to test more efficiently. The types of the bugs the tool found are the ones we wouldn’t catch with regression tests.

     

    When installing the tool, after setup is launched, you will get a dialog like the following:

     

    clip_image002

     

    If you select Yes, the test will start whenever the logon user to a machine has been idle for 30 minutes or more and the test will stop when you come back to your machine. So it will utilize the time to automatically run the tests whenever you are away from your computer 30 minutes or more. You can select No if you don’t want this option. If No is selected, test would only run when you start it explicitly (from CodeInjector context menu “Start Testing”, see below for details).

     

    CodeInjector Menu Options:

    After CodeInjector starts, a notify icon (with the name CI inside the icon) will be displayed in your system tray area. Right click the icon gives you the following menu options:

     

    clip_image004

     

    ·         Start Testing – gives you the flexibility to start testing explicitly if you want to.

    ·         Stop Testing – gives you the flexibility to stop testing if testing was started explicitly.

    ·         Use Private Test File – CodeInjector is configured to use test sources from the Compiler QA source directory. But you can select this menu to use your own private test files. Clicking this menu brings up the following dialog:

     

                                                                                                     clip_image006

    • Click “Browse…” will bring up a folder selection dialog to select the folder where your private test files are. And the folder path you select will be displayed in the text box to the left of the browse button.
    •  “Use Default Path” button will reset the test sources folder to the default one CodeInjector is configured to use.

    ·         Show Testing Summary – Click this menu will pop up a message box telling you how many test files have been processed, how many issues (failures) have been hit , and the mean time to find a failure.

     

    clip_image008

     

    ·         About – Click this menu shows a dialog about CodeInjector such as version, CopyRight information, and description of CodeInjector etc.

    ·         Exit – This exits CodeInjector.

     

    Some features of the tool:

    ·         Easy to set up

    ·         Tests automatically start when your machine is idle for 30 minutes or more.

    ·         Tests automatically stop when you are back to your machine.

    ·         The tool gives you the flexibility to also explicitly start and stop testing.

    ·         The tool has been deployed through ClickOnce. So if there is an update, the update will be picked up next time you restart the tool.

     

    Test source files:

    The tool currently is using code files from the Compiler QA source directory. You don’t need to have these source files on your local machine. CodeInjector is configured to look for these files from a specified location. You do have the option to specify your own sources though. You can do this by clicking the menu “Use Private Test File”.

     

     

  • Testing using WPF UI automation

    I just ran across Lester's blog post Testing using WPF UI automation, which is definitely worth sharing here. It looks like testing WPF UI will be much easier than testing native/WinForms UI.

    Kirill Osenkov, C# IDE QA

  • Using Reflection to automate testing of an .exe file

    Hi all,

    My name is Kirill Osenkov and I am a new member of the C# IDE QA team. I'm hoping to post articles related to C#, testing and other interesting areas to our teams blog. I also have a personal blog over at http://kirillosenkov.blogspot.com, where I post random thoughts about .NET, design and developer tools.

    Today I'd like to discuss a technique to programmatically access the internals of .NET executables, and invoke them from code, and not through the user interface. We'll use reflection to test one of the C# LINQ samples that ship with Visual Studio 2008.

    Why do samples need automated testing anyway?

    If you open VS 2008 and go to Help -> Samples -> Samples on Disk, you'll see a link to a .zip file containing all of the C# samples, similar to this: \Program Files\Microsoft Visual Studio 9.0\Samples\1033\CSharpSamples.zip. In folder LinqSamples, there is a WinFormsDataBinding project, and we'd like to write a test for this sample that ensures that the sample works fine.

    First, you might ask, why bother and write a test for the samples at all? You can just open it, hit F5, and spend 20 seconds to test the sample functionality. Well, during the development of a feature such as LINQ a lot of things can change often - the syntax, the libraries etc. You don't want to manually open each sample and verify that it still works every time our developers change a feature. It is nice to have a set of automated tests that can ensure:

    1. if the sample still works, this means that the changes to the product feature (LINQ) haven't introduced new bugs in most common scenarios (samples actually are perfect tests for common usage scenarios!).
    2. if the sample is broken, we'll investigate and either find a bug in the feature or update the sample to correctly use the feature.

    In any case, we won't forget to update the samples to correctly work with the latest version of the product, and if the sample tests pass, this is generally a good indication of a working product - awesome for quick sanity check of main functionality.

    Different ways to test a sample

    When you build the sample, you get a .NET executable. If it exposes public types and members, you can just add the assembly as a reference to your test and directly call those members. Such "access points" that are specifically there to facilitate testing are called test hooks and their purpose is to expose an API externally to allow tests to manipulate the functionality. If a product provides good, easy to use test hooks, it is said to be testable, which means you can easily write a test program to invoke the functionality of the product.

    But what if the sample wasn't specifically designed to be testable? Mostly, samples tend to be small, simple pieces of code, designed only to demonstrate some basic concepts. We don't want to make the samples more complicated by providing test hooks, as it might confuse and distract those who study the sample. So, we come to a constraint - we can't change the sample to be testable - we have to live with what we have. And often, we only have private types and members - adding the sample assembly as a reference to our test project won't help anymore. So the problem boils down to: how to invoke private API's of a .NET assembly from another assembly?

    A scenario to test

    We have a WinFormsDataBinding project. If you build and run it, it will display a form with a list of employees displayed in a grid:

    image

    Our goal is to pretend that we are a user who:

    1. opens the main form
    2. changes the last name of employee with ID 1
    3. submits the changes to the database
    4. closes the main form
    5. reopens the form
    6. verifies that the last name of employee #1 was indeed changed
    7. changes the last name back to the old one
    8. submits the changes
    9. closes the form

    Actually, only steps 1-6 are necessary to verify the basic functionality of the LINQ to SQL data binding. Steps 7 and 8 are only necessary to make the test repeatable - this means we can run the test multiple times without side effects. This is a quality of a good test: repeatable means atomic and side-effects-free.

    Using Reflection

    In our test project, we first want to open the main form. All we have is an .exe file on disk, which is built when you compile the WinFormsDataBinding project. To be able to access the internals of the .exe, we must first load the assembly into memory (into our application domain, to be more specific):

                // Load an assembly from file
                string fileName = Path.Combine(Application.StartupPath, "WinFormsDataBinding.exe");
                Assembly winFormsDataBinding = Assembly.LoadFile(fileName);

    Don't forget to add using System.Reflection; to be able to use reflection.

    1. Open the form

    The main form is represented by the WinFormsDataBinding.EmployeeForm type in the WinFormsDataBinding assembly. Let's just load the type from the assembly:

                Type formType = winFormsDataBinding.GetType("WinFormsDataBinding.EmployeeForm", true, true);

    Now that we have the type of the form, we can create an instance of this type (a Form to show). Let's create a method that will do that for us:

            Form ShowForm(Type formType)
            {
                Form newForm = Activator.CreateInstance(formType) as Form;
    
                newForm.Show();
                newForm.Refresh();
                Application.DoEvents();
                return newForm;
            }

    We use System.Activator.CreateInstance to create a new instance of the form, and then we show it on the screen and redraw, so that we actually see that the form is there. I don't include any error handling to simplify the code (normally you would like to surround the first line in a try-catch block in case something goes wrong).

    2. Change the cell in the data grid

    Let's write a method for this:

            void SetCellText(Type formType, string newName)
            {
                Form newForm = ShowForm(formType);
                DataGridView dataGrid = FindDataGrid(formType, newForm);
                DataGridViewCell cell = FindCell(dataGrid);
                cell.Value = newName;
                PushSubmitChangesButton(formType, newForm);
                CloseForm(newForm);
            }

    First we use the ShowForm method to create an instance of the form and show it. Then there are two additional steps involved: we have to find the data grid object on the form and then find the required cell in the data grid. Here's the FindDataGrid method:

            DataGridView FindDataGrid(Type formType, Form newForm)
            {
                FieldInfo dataGridField = formType.GetField(
                    "employeeDataGridView", 
                    BindingFlags.NonPublic | BindingFlags.Instance);
                DataGridView dataGrid = dataGridField.GetValue(newForm) as DataGridView;
                return dataGrid;
            }

    We use the GetField method on the Type class to find a private field called 'employeeDataGridView'. Then we extract the value of this field from our Form object, which gives us a reference to the DataGridView object.

    Now we want to find a cell in this grid:

            /// <summary>
            /// Finds the required cell in the grid 
            /// (last name of employee #1)
            /// </summary>
            DataGridViewCell FindCell(DataGridView dataGrid)
            {
                int rowNum = FindRow(dataGrid);
                DataGridViewCell cell = dataGrid.Rows[rowNum].Cells[2];
                return cell;
            }
    
            /// <summary>
            /// Finds the row number with ID = 1 in the grid
            /// </summary>
            int FindRow(DataGridView dataGrid)
            {
                for (int i = 0; i < dataGrid.Rows.Count - 1; i++)
                {
                    if (dataGrid.Rows[i].Cells[0].Value.ToString() == "1")
                    {
                        return i;
                    }
                }
                return 0;
            }

    If we go back to our SetCellText method, we'll see that actually changing the cell's value is easy:

                cell.Value = newName;

    3. Submit the changes to the database

    To submit the changes, we must programmatically push the 'Submit changes' button on our form. The method PushSubmitChangesButton does that:

            void PushSubmitChangesButton(Type formType, Form newForm)
            {
                MethodInfo submitChanges_Click = formType.GetMethod(
                    "submitChanges_Click", 
                    BindingFlags.Instance | BindingFlags.NonPublic);
                submitChanges_Click.Invoke(newForm, new object[] { null, null });
            }

    Again, we use reflection to fish out a private method from the form's type, and then we invoke the method on the newForm object (passing nulls as arguments).

    4. and 5. Closing and reopening the form

    Closing and reopening the form is easy, we just call Close() on the form object and call ShowForm to show a new instance of the form.

    6. Read the contents of the data grid cell

    The GetCellText method is very similar to SetCellText:

            string GetCellText(Type formType)
            {
                Form newForm = ShowForm(formType);
                DataGridView dataGrid = FindDataGrid(formType, newForm);
                DataGridViewCell cell = FindCell(dataGrid);
                string result = cell.Value.ToString();
                CloseForm(newForm);
                return result;
            }

    7. 8. and 9. Complete the test

    Finally, here's the complete code of our test:

                string fileName = Path.Combine(Application.StartupPath, "WinFormsDataBinding.exe");
                Assembly winFormsDataBinding = Assembly.LoadFile(fileName);
    
                Type formType = winFormsDataBinding.GetType("WinFormsDataBinding.EmployeeForm", true, true);
                
                SetCellText(formType, "Smith");
                string newName = GetCellText(formType);
                if (newName != "Smith")
                {
                    throw new Exception("It didn't rename");
                }
                SetCellText(formType, "Davolio");
    Summary

    In this tutorial we've used reflection to:

    • load an assembly
    • find a type in it
    • create an instance of this type
    • read a field on that instance
    • call a method on that instance

    Please let me know if you have any questions or want me to clarify anything.

    Thanks,

    Kirill

  • Is a tester ever done with testing (Part 2)

    Hope you got a small glimpse of a my world as a tester in my previous post.

     

    This post continues to shed light on more specifics of testing I have witnessed my team do and how it contributes to the we-will-never-get-done attitude I mentioned in my previous post.

     

    As you might already know, we test C# IDE in our team. Testing C# IDE, which is just a part of the whole Visual Studio product (VS for short, from now on), basically boils down to testing a handful of components that go into building all of the C# IDE features into the product. While it is obvious that we are most of the times just testing these components, we also have to test for the following real world/customer scenarios to make sure the IDE features work just great.

     

    -          Side by side scenario: This refers to having an older version of VS on the same machine with side by side newer version (which is of interest to us for now since it is this newer product that we are going to ship this time) on the same machine. This scenario calls for validating that

    ·        the newer version of VS installs fine side by side with an older version of VS.

    ·        the older and the newer version continue to work as expected in this side by side situation

    ·        the uninstall of any one of the products leaves the remaining one(s) in a good functioning condition

     

    -          Vertical integration scenario: This refers to having a higher order SKU of VS side by side with a lower order SKU of the same version of the product on the same machine. SKUs of VS can be

    o    role based (developer, architect, tester) or

    o    the one that has all the roles rolled into it  (Team suite) or

    o   simple express editions that cater to very lightweight, non-professional and hobbyist developers or

    o   the ones that cover core grounds of development like Professional (PRO), Standard (STD) and the one for office (VSTO)

    More on SKU and their differences for VS2005 can be learned here and here.

    Testing this scenario validates that

    ·        a lower order SKU and higher order SKU can be installed side by side

    ·        both lower and higher order SKUs work as expected

    ·        the uninstall of one will not affect the remaining SKU in any unexpected way

     

    -           App Isolation scenario: All the express editions of VS (C#, C++, Web and VB) can all be installed side by side on the same machine and testing this scenario aims to validate that

    ·        all the express editions function well as expected side by side

    ·        uninstall of one or more of the express editions leave/s the remaining one(s) unaffected

     

    Testing that the product of interest works fine in the above scenarios requires us to run our tests in the above various combinations of product configurations. For example – we test to make sure that C# IDE works fine on VS2008 with VS2005-SP1 and VS2008 on the same machine, that the C# IDE works fine on C# Express on a machine with C# express and web express with web express uninstalled later on.

     

    Apart from these SKUs, VS gets translated into 8 more languages other than English which are Simplified-Chinese, Chinese-Taiwanese, Japanese, Korean, French, Italian, German and Spanish. Our tests that validate the correct functioning of C# IDE should also run on these language products to make sure our localized version of IDE works on par with the English one.

     

    There is one more interesting scenario in which the product is used and that is “Globalization” scenario. This refers to using English VS on top of a non-English operating system (OS). This is to cater to those customers that belong to certain parts of the world where English is pretty commonly used along with their native languages and people there are expected to use our English VS products on their native language version of OS’s. Testing this scenario validates that

    ·        IDE is Unicode-compliant

    ·        IDE is capable of handling Unicode and left-to-right or bi-directional languages as inputs in code editor, dialog input boxes etc

    ·        IDE is capable of receiving inputs from non-English keyboards, etc

     

    Examples of this testing include – making sure that the C# IDE in VS works fine when installed on a machine with Arabic Windows XP etc

     

    Machine architectures also play a role in this whole of test matrix and we need to test on x86 and x64 platforms to validate we are good to go on these as well.

     

    Added to this whole set of things are the different OS’s themselves – like Windows XP, Windows 2003 Server, Windows Vista etc as they ship one or more versions of the .NET framework, an OS component that the VS is very closely bound to.

     

    One last interesting element in this already huge test matrix is that our C# IDE components are  invoked from various other clients within the VS –for example, C# intellisense has to work in immediate window in debug mode, most of the C# IDE features have to work in a web project or website project also, etc.

     

    One good thing in all this seemingly infinite set of possible test scenarios is that we can still use the same set of tests over and over again to validate our part of the product without having to author special tests for any of the configurations. It is, however, obvious that just running the already written tests over and over again on these hundreds of configurations requires time, effort and resources.

     

    The important point of view I gain as a tester, which is easy for a developer to miss, is that a feature needs to be developed once but needs to be tested in hundreds of ways before we can sign off on it as good enough to be shipped. In doing this, we testers tend to become the most expensive part of the whole product building process that I briefly described in my previous post.

     

    Hopefully I provided a small insight into a tester’s world by describing all the elements one is required to go against while assuring the quality of the product as being shippable.

     

  • C# IntelliSense tests

    C# IntelliSense tests

     

    Hi, I am Jeremy Meng from the C# QA team. I mainly work in testing the C# IntelliSense area.  C# IntelliSense is a set of IDE features that help C# developers write their code faster and less error-prone. Examples of these features include

     

    ·         Quick Info. The yellow tooltip window with information while hovering over an identifier

    quick info

    ·         Parameter Help. The yellow tooltip window showing the signature of the method and the parameter being typed

    parameter help

    ·         Completion List.  The list box containing a set of completion candidates for developer to use

    completion list

     

    The goal of our tests is to ensure that the IntelliSense features work correctly as expected.

     

    Good automated tests should be easy to maintain and easy to investigate when there are failures.  They should run as fast as possible too.  These good qualities would make our test pass runs shorter, thus enable us to do more runs to discover more potential issues.

     

    In the past most of our C# IntelliSense tests use UI tests.  We have libraries that enable us to navigate, validate and manipulate the UI of any Windows-based application.  Take the Quick Info feature for example.  If we want to validate the Quick Info text for a certain identifier in a C# source file opened in Visual Studio, we can use API’s to move the cursor to the position of the identifier, invoke the feature to display the Quick Info, then capture the text in the tooltip window.  All of these can be done programmatically. An automated UI test behaves almost as same as a tester would perform the test manually.  So it’s most desirable if we want our tests to be as close to the real usage case as possible.  UI tests are also useful when there are no other existing frameworks to test a feature.  However there are several issues for pure UI tests.  They are slow.  Synchronization problems (timing issues) happen frequently in and many of the issues are hard to debug too.  So currently we are trying to reduce the usage of UI tests and write tests in other better ways that don’t involve many UI interactions.

     

    For some parts of the automation we can use Visual Studio Extensibility.  Visual Studio Extensibility is an assembly-wrapped COM library containing the objects and members for Visual Studio core. Things that Visual Studio Extensibility can do include creating solutions and projects, adding files, accessing core Visual Studio windows, executing Visual Studio commands, etc. without having to click menus and dialogs.  Although Visual Studio Extensibility is non-UI, it only has VS core functionalities.  To test our C# IntelliSense features in a non-UI way, we have to have more.

     

    Instead of manipulating the UI to validate a feature, we can test the feature directly. To achieve this we do tests on component level.  Look at the Quick Info example again.  We could ask the C# IntelliSense Engine directly: What quick info would you show for the identifier at line x, column y in the editor?

    We can then validate the text by either using a baseline, or some other kinds of dynamic verification logic, thus avoid going through the UI to obtain the quick info text.

     

    Currently we can do component-level tests for IntelliSense features like Quick Info, Parameter Help, Completion Lists, as well as for other C# IDE features like Find All References, Go To Definition, Extract Method, Format, etc. 

     

    We do component-level testing in two kinds of tests: semi-UI tests and non-UI tests.  The two kinds of tests both have their pros and cons.

     

    In the semi-UI test, we start an instance of VS, set up the solution and project, open the source file, then invoke the test hook and validate the feature.  In such a test the feature is tested in a real C# project in the real Visual Studio.

     

    Pros:

    ·         Closer to real world scenarios.

    ·         Availability of automation support from Visual Studio

    ·         Covering integration of C# language service features and Visual Studio as well

     

    Cons: 

    ·         Starting and setting up Visual Studio take a lot of time.

    ·         Not 100% focus on testing language service features

     

    For non-UI tests, we have a framework called Stand-Alone-Language-Service-API (SALSA).  SALSA utilizes the unit test framework that our developers are using.  In a SALSA test, we don’t start a Visual Studio instance.  We are using a mocked environment and other mocked services that are necessary to test the IDE language service features.  Our data show that SALSA tests are at least 90% faster than the semi-UI tests.

     

    Pros:

    ·         Much faster

    ·         Focus on features

     

    Cons:

    ·         Mocked environment not the same as the real Visual Studio

    ·         Tests are limited by the developers' unit test framework so there are tests that can’t be written in SALSA

     

    Conclusion:

     

    We want to increase the percentage of non-UI tests since it’s much faster while keep enough amount of UI tests because they can cover integration and they are closer to the real usage scenarios.

  • Is a tester ever done with testing? (Part 1)

    My name is Suma Sushilendra and I have been a tester in C# IDE team since August ’02. I have owned testing C# IDE features for Visual Studio 2003, Visual Studio 2005 and now for Visual Studio 2008, also known as “Orcas”. Over these products and the last 5 years, I have owned testing almost all the IDE features except refactoring and debugging features.

     

    There is so much that can be spoken of testing and here I am setting stage for a burning question that has continued to amuse me for the past 5 years of life as a tester, at every cycle during a product development.  What I present here is entirely how I feel and deal with it.

     

    When I began my career as a tester, there were a few basic rules of the road that I became familiar with and got to learn a set of processes and methodologies to follow along with some tools in order to make progress in the testing tasks I was made the owner of. As time grew, the tasks became responsibilities and owning testing of a feature became really being accountable for its quality.

     

    Just for the sake of simplicity, let’s define (re-define) a few terms for making the point that this blog post is trying to.

     

    Product – A software application with a bunch of old and new features aimed at aiding, enhancing and easing targeted activity/activities of its customers.

     

    Feature – A small part of a product whose purpose of existence in the product is to help in a focused activity that the customer of the product is known/expected to indulge in often.

     

    Project – A group of management people and processes that work around the people who do the real work, driving the timelines for releasing the product, controlling the logistics of how the product is developed (in stages), making sure that the list of features therein are in alignment with the customer expectations etc. Basically this is a necessary evil to every product’s release.

     

    Customer – User of the product, of course!

     

    One of the very first questions that the project management has to come up, even before deciding what the new product is actually going to be, is – when is it going to be released for public consumption? This boils down to asking every faculty of product making – when are you going to be done? And the fun begins when this question is popped. Broadly looking at the various faculties that are involved in the actual product building (I am leaving out the aspects of research that goes into deciding what all features to embed in a product, what are the customer expectations, what are the competitor products in the same line etc for the purpose of keeping this discussion concise and focused), I can say there are

    -          Designers

    o   who understand how the features are going to be used by the customers

    o   who are expected to be more in touch with the customers’  and the competitor’s world

    o   and thereby hold a say in deciding if a feature needs to exist in a product

    -          Developers

    o   who are the builders of the features/products

    o   who also have a good understanding of customers

     

    -          Testers

    o   who make sure the feature/product quality meets the expectations of customers buying the product

    o   who also have a good understanding of customers and their needs and pain points

    o   who get to use the product soon after it is built and hence, get to experience the joy as well as pain of having to do so

     

    That said, let me come back to the title of the topic – it is very important to note that the above list of faculty almost operates in that chronological order too. So we, the testers do happen to find ourselves at the last step of the product development process. So while this “when are you going to be done?” is an important question to answer for all the above faculties, it is more so for testers because we seem to be that last stop in the journey of the product that takes it out of the company’s doors and into the hands of eagerly waiting customers. Needless to say that it is at this moment that takes the product to its intended destination that the whole team’s efforts seem all more worthwhile. In that respect, when we testers, sit between the product and the customers, it is almost like saying that when testers get done, the product gets done!

     

    And there can’t be more truth to it! So how do we say we are done? Simple, if you happen to say “yes” to the questions below, you are probably done testing that feature!

     

    -          Is the feature code frozen? (Meaning no more change will be accepted)

    -          Is the test plan complete?

    -          Is the “planned” testing (automated, manual, end-to-end or whatever) done executing?

    -          Have we stopped finding serious bugs in the mainline customer scenarios as well as some complicated use cases, for quite a while now?

    -          Have all of our tests been consistently passing of late?

    -          Do we feel that the feature meets the customer expectation?

     

     

    If you notice, I said “you are probably done testing that feature!”. Then when will you be really done? Ok, let me take you through a small dramatized version of this conversation that happens between me and the team. Lines that are italicized are my mental conversations, just so you know!

     

    My Manager : So, are you done testing this feature now? (Note that I said “yes” to all the questions above)

    Myself           : Yes, I think so    ( Whatever I said after “yes” drives my manager nuts sometimes)

    My Manager : Are you sure?  

    Myself           : (…well, I am, only until my customer finds a bad bug that I missed!) Yes, I did do everything that I had planned for testing this feature and it does look like I am done, as of now

     

    At this point, my manager usually gets what I meant without me further having to explain.

     

    Our mission is accomplished when we ship our product. I do feel that we testers are an important and necessary “obstacle” before we accomplish our mission. Although we fall short of a customer just for the fact that we don’t spend our hard earned money to buy the product like our customers do, if you can believe me, we feel worse than having wasted the money on a low quality product when we see a customer run into a bad issue that makes his/her work stop/go waste. More so, because we had the chance to go through that pain ourselves thereby not have our customers discover it. We do know like everyone in software making, that no software is absolutely bug free but all we try to make sure is that we know all or most of its bugs before we ship.

     

    It has been quite a fun filled roller coaster ride seeing some features getting rave reviews and some features becoming real pain for customers for me over the last 2 products that I have been involved shipping in. It is always a mixed bag of complaints and accolades when it comes to how our features are seen and used by our customers. In my next blog, I plan on exploring  more into the details to explain the reason behind this we-will-never-get-done attitude of ours for all the testing we have to do.

     

     

  • Rename Refactoring on Anonymous Types

    Hi,

    My name is Rahul Bhandarkar and I work on the C# IDE QA team. I have spent most of my time working on the Refactoring and Project System features, in the past I have also worked on Snippets and Edit-and-Continue.

    Rename Refactoring is a code refactoring we introduced in VS2005, it allows a user to rename a symbol in code and have its definition and all the references updated.

    For example:

    public class A                                       

    {       

       int p;

       void M()

       {

         if (p > 0)

         p = 0;

        }       

    }

    If you Invoke Rename Fefactoring on p and rename it to q, the definition and all references to the symbol p, will now be updated to q.

    public class A

    {       

       int q;

       void M()

       {

         if (q > 0)

         q = 0;

        }       

    }

    Anonymous Types  is a new C# 3.0 language feature introduced in VS 2008. An anonymous type is nameless class type that derives from object and has a sequence of read-only properties that are initialized using member-initializers. Anonymous types are immutable, i.e. once they are constructed, the properties are read-only. Let’s look at an example:

    var foo = new { A = 1, B = "hello world" };

    If you examine the IL that the compiler produces for this, you will see a compiler-generated type with a random name that usually ends with __AnonymousType, and contains two properties, a property A of type int and a property B of type string, both properties only have getters (i.e. they are read-only).

    A member-initializer can take the following forms:

    Simple Name: var foo = { x }; 

    Member access: var foo = { bar.x }; 

    Explicit Name: var foo = { Prop = x }; 

     

    Type Unification

    The compiler unifies anonymous types that define a sequence of properties of the same type specified in the same order.

    Example:

       var order = new {ID = 1, City=”London”}

       var customer = new { ID = 1000, City = “Seattle”}

    The variables order and customer have the same underlying anonymous type. A side-effect of this with respect to Rename Refactoring is that a Rename on order.ID will also trigger a Rename on customer.ID.

       var order = new {ID2 = 1, City=”London”}

       var customer = new { ID2 = 1000, City = “Seattle”}

    Note that this effect is restricted to the method in which the Rename is invoked in.

    Introducing Named Properties

    Previously in the C# language we did not have declarations that could also be references. So when we invoked Rename on a symbol we knew exactly if we were trying to rename a definition of a reference. Now with the Simple name member-initializer, we have a situation where “x” is a declaration of the Anonymous Type property and a reference to another local. So what is the effect of renaming “x” ? We decided that only in the case where it was absolutely clear what the user was trying to rename (Explicit Name Member initializer) we would invoked the Rename on the property name. In the other two cases we would treat it as a rename on the reference.

    Lets see how that works,

    int x = 10;

    var foo = { x }; 

    Rename on x at either location will give us.

    int x2 = 10;

    var foo = { x2 }; 

    But what if there other variables that refer to foo, all of them would have to be modified.

    int x = 10;

    var foo = new { x };

    var bar = new {foo.x}; 

    var m = bar.x;

    var baz = new { bar.x };

    This would lead to a cascading effect which was undesirable. In order to preserve the semantics of the anonymous type we decided to introduce a named property.

    int x2 = 10;

    var foo = new { x = x2 };

    var bar = new {foo.x};

    var m = bar.x;

    var baz = new { bar.x };

    I find Code Refactoring very interesting and as the language evolves there are several interesting Refactorings that make writing and modifying code easy and fun, after all we are about developer productivity. So I welcome your feedback/suggestions on existing and ideas for new Refactorings.

     

  • Welcome

    Welcome to the Visual C# Quality Assurance (QA) team blog.

    We work closely with developers and program managers to define and create features.  We own finding the bugs, defining test strategies, creating automation, and writing tools that do testing for us.  We help define and decide when a product is ready to ship.

    We are responsible for testing the C# editor and its many features, including:

    • IntelliSense
    • formatting
    • colorization
    • navigation
    • refactorings

    We decided to start blogging because we want to connect more with the testing community and our customers.  We want to chat about some of the things we have learned or are working on.  We would also love to hear your feedback on the Visual C# IDE and how we can make it better.

    In our blog we will chat about C#, C# IDE features and testing in general.  We will share more on how we hone C# features into the final product.  This process of honing is reflected in our blog name "CSharpening."

    Thanks for dropping by!

    Damon

    Visual C# QA


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