{"id":4573,"date":"2012-08-16T22:40:00","date_gmt":"2012-08-16T22:40:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2012\/08\/16\/few-tips-on-implementing-a-coded-ui-test-plugin-extension\/"},"modified":"2019-02-14T17:59:05","modified_gmt":"2019-02-15T01:59:05","slug":"few-tips-on-implementing-a-coded-ui-test-plugin-extension","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/few-tips-on-implementing-a-coded-ui-test-plugin-extension\/","title":{"rendered":"Few tips on implementing a Coded UI Test Plugin Extension"},"content":{"rendered":"<p>This blog assumes that you have a prior understanding of Coded UI Test extensibility. If not, a good starting point would be <a href=\"http:\/\/blogs.msdn.com\/b\/gautamg\/archive\/2010\/01\/05\/series-on-coded-ui-test-extensibility.aspx\">here<\/a>. Also check out additional links in the <em>&ldquo;Extending Coded UI Test&rdquo;<\/em> section available&nbsp;<a href=\"http:\/\/blogs.msdn.com\/b\/mathew_aniyan\/archive\/2009\/12\/10\/content-index-for-coded-ui-test.aspx\">here<\/a>.<\/p>\n<p>In this post, I&rsquo;ll enumerate a few points you would need to watch out for while implementing an extension plugin. Some of the data are a compilation of actual issues the plugin writers hit while developing their plugin in collaboration with the Coded UI Test team.<\/p>\n<p><span style=\"font-size: small\"><strong>1. Set the ComVisibleAttribute <\/strong><\/span><\/p>\n<p>Ensure that the System.Runtime.InteropServices.ComVisibleAttribute is set to true for both technology manager and technology element class. For example,<\/p>\n<p style=\"padding-left: 30px\"><code class=\"csharp\"> [ComVisible(true)]<\/p>\n<p> public class TelerikGridViewTechnologyElement : UITechnologyElement { &hellip; }<\/p>\n<p> [ComVisible(true)]<\/p>\n<p> public sealed class TelerikGridViewTechnologyManager : UITechnologyManager { &hellip; }<br> <\/code><\/p>\n<p><span style=\"font-size: small\"><strong>2. Implement some caching mechanism for properties in property provider. <\/strong><\/span><\/p>\n<p>You could be using different approaches for fetching the control properties. It could be through an accessibility interface or some code injection technique with some remoting mechanism to communicate between the two processes.&nbsp; Either way, always ensure that you property fetching is optimized,&nbsp;specifically&nbsp;for properties whose value remain constant throughout.<\/p>\n<p>A good example is ControlType. This property is accessed a lot number of times on each PropertyProvider call at different contexts.&nbsp; Ensure that such property values for the controls are cached in your plugin. Secondly, use lazy initialization for the property values. Use your own diligence to decide on whether to do bulk fetching versus individual property fetching. At instances we have observed as much as 3x improvement in performance with proper level of caching implemented.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-size: small\"><strong>3. Limit the hierarchy for the specialized class<\/strong><\/span><\/p>\n<p>Ensure you provide the correct level of ancestor in the hierarchy. For example, the Desktop UITestControl need not be specified as the container for the TopLevelWindow. It simply creates an unnecessary hierarchy during CodeGeneration. &nbsp;<\/p>\n<p><code class=\"cplusplus\">&nbsp; public WpfInjectedWindow() : base(UITestControl.Desktop) { &hellip; }<\/code><\/p>\n<p>Instead, simplify it as<\/p>\n<p><code class=\"cplusplus\">&nbsp; public WpfInjectedWindow() : base(null) { &hellip; }<\/code><\/p>\n<p>&nbsp;<br><span style=\"font-size: small\"><strong>4. Do not access &ldquo;live&rdquo; UITestControl properties in UITestPropertyProvider.GetControlSupportLevel(UITestControl)<\/strong><\/span><\/p>\n<p>No&nbsp;new property fetching should be done within the GetControlSupportLevel() method. The UITestControl passed to this method may not necessarily be a &ldquo;live&rdquo; control i.e. may not exist currently in the desktop session. (Note: The GetControlSupportLevel() is called both in the context of Playback as well as CodeGeneration). So the decision of support level should be based solely on the static information available in the UIObject map i.e. search properties, technology name, etc.<\/p>\n<p>Here is an example that makes use of ClassName and AccessibleDescription values from the UIObject search properties.<\/p>\n<p><span style=\"font-family: courier new,courier\">public override int GetControlSupportLevel(UITestControl uiTestControl) <\/span><br><span style=\"font-family: courier new,courier\">{ <\/span><br><span style=\"font-family: courier new,courier\">&nbsp; bool useClassName = false; <\/span><br><span style=\"font-family: courier new,courier\">&nbsp; string className = string.Empty;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;string accDescriptionValue = string.Empty;&nbsp;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;if (uiTestControl.SearchProperties != null &amp;&amp; uiTestControl.SearchProperties.Count &gt; 0)&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;{&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; PropertyExpression controlTypeExpression = uiTestControl.SearchProperties.Find(&ldquo;ClassName&rdquo;);&nbsp;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;if (controlTypeExpression != null)&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; className = controlTypeExpression.PropertyValue; useClassName = true;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<\/span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;controlTypeExpression = uiTestControl.SearchProperties.Find(&#8220;AccessibleDescription&#8221;);&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;if (controlTypeExpression != null) <\/span><\/p>\n<p><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; { <\/span><\/p>\n<p><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accDescriptionValue = controlTypeExpression.PropertyValue;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; } <\/span><br><span style=\"font-family: courier new,courier\">&nbsp; }&nbsp;&nbsp;<\/span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;\/\/ Use this &#8216;accDescriptionValue&#8217; and &lsquo;className&rsquo; for all your decision making.&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;\/\/ Do not call uiTestControl.GetProperty(&#8220;AccessibleDescription&#8221;) or uiTestControl.GetProperty(&#8220;className&#8221;)&nbsp;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;if (string.Equals(uiTestControl.TechnologyName, &ldquo;TelerikGridView&rdquo;, StringComparison.OrdinalIgnoreCase)&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; (!useClassName || string.Equals(className, TelerikGridViewConstants.TelerikGridViewClassName, StringComparison.OrdinalIgnoreCase))&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp; accDescriptionValue.Contains(&#8220;Telerik.WinControls.UI.GridView&#8221;))&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;{&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; return (int)ControlSupport.ControlSpecificSupport;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;}&nbsp;<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;return (int)ControlSupport.NoSupport;&nbsp;<\/span><br><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<p>Also, note the difference between the UITestPropertyProvider.GetControlSupportLevel(UITestControl) and UITechnologyManager.GetControlSupportLevel(IntPtr). The latter is used by the recorder and Coded UI Test control locator on a live control. So it is fine to access the live information of the control (corresponding to the window handle passed) in this method.<\/p>\n<p><strong><\/strong>&nbsp;<\/p>\n<p><span style=\"font-size: small\"><strong>5. Do not use the existing core technology manager names.<\/strong><\/span><\/p>\n<p>The Core technology managers have reserved names.<\/p>\n<p><code class=\"cplusplus\"><span style=\"font-family: courier new,courier\"> const string WindowTechnologyName = \"Window\";<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\"> const string MsaaTechnologyName = \"MSAA\";<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\"> const string WebTechnologyName = \"Web\";<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\"> const string UiaTechnologyName = \"UIA\";<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\"> const string SilverlightTechnologyName = \"Silverlight\";<\/span><br><\/code><\/p>\n<p>Ensure you provide an unique name to the extension plugin manager. If there is any name conflict, the extension manager will load the plugin, but will fail to register it to the recorder or playback. As a result, the plugin is rendered useless.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-size: small\"><strong>6. Avoid specific implementation inside the Specialized class properties.<\/strong><\/span><\/p>\n<p>This is particularly&nbsp;of relevance if you are using the plugin for both Coded UI Test as well as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd380763.aspx\">MTM<\/a>. The property fetcher implementation should reside on your common property provider&rsquo;s UITestPropertyProvider.GetPropertyValue(UITestControl, string) implementation. The specialized class property should just be a thin layer calling into the UITestControl.GetProperty()<code class=\"csharp\">&nbsp;<\/code><\/p>\n<p>&nbsp; <span style=\"font-family: courier new,courier\">&nbsp; public class TelerikGridViewCell : WinControl<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; {<\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp; &#8230; <\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp; public virtual string BorderColor <\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp; { <\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return (string)this.GetProperty(PropertyNames.BorderColor); } \/\/ This internally invokes UITestPropertyProvider.GetPropertyValue(). <\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp; } <\/span><br><span style=\"font-family: courier new,courier\">&nbsp;&nbsp; }<\/span><\/p>\n<\/p>\n<p><span style=\"font-size: small\"><strong>7. Make use of the new extension proxy classes<\/strong><\/span><\/p>\n<p>You could be implementing support for a completely different UI Technology or you goal could be to create add-on support or customization over existing UI technologies supported by coded UI Test. For the latter, make use of the new extension proxy classes recently released&nbsp;that simplifies the implementation to a great extent. The details are available <a href=\"http:\/\/blogs.msdn.com\/b\/visualstudioalm\/archive\/2012\/05\/24\/coded-ui-test-new-extensibility-qfe.aspx\">here<\/a>.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog assumes that you have a prior understanding of Coded UI Test extensibility. If not, a good starting point would be here. Also check out additional links in the &ldquo;Extending Coded UI Test&rdquo; section available&nbsp;here. In this post, I&rsquo;ll enumerate a few points you would need to watch out for while implementing an extension [&hellip;]<\/p>\n","protected":false},"author":107,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229,1,252],"tags":[],"class_list":["post-4573","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-community","category-devops","category-testing"],"acf":[],"blog_post_summary":"<p>This blog assumes that you have a prior understanding of Coded UI Test extensibility. If not, a good starting point would be here. Also check out additional links in the &ldquo;Extending Coded UI Test&rdquo; section available&nbsp;here. In this post, I&rsquo;ll enumerate a few points you would need to watch out for while implementing an extension [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/4573","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/107"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=4573"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/4573\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=4573"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=4573"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=4573"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}