<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:media="http://search.yahoo.com/mrss/"
		>
<channel>
	<title>Comments for Jian Fang's Weblog</title>
	<atom:link href="http://johnjianfang.wordpress.com/comments/feed/" rel="self" type="application/rss+xml" />
	<link>http://johnjianfang.wordpress.com</link>
	<description>Just another WordPress.com weblog</description>
	<lastBuildDate>Sat, 19 Jul 2008 15:29:03 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>Comment on The abstract object based Selenium Test framework (AOST) by johnjianfang</title>
		<link>http://johnjianfang.wordpress.com/2008/07/08/the-abstract-object-based-selenium-test-framework-aost/#comment-3</link>
		<dc:creator>johnjianfang</dc:creator>
		<pubDate>Sat, 19 Jul 2008 15:29:03 +0000</pubDate>
		<guid isPermaLink="false">http://johnjianfang.wordpress.com/?p=3#comment-3</guid>
		<description>Groovy Patterns Used in AOST

In AOST(http://code.google.com/p/aost), we used many Groovy patterns. I like to list some of them as follows,

1) BuildSupport

BuildSupport is very powerful for parsing nested definitions, such as XML markup. In AOST, the buildsupport is used as UI object definition parser and it is one of the bases for our internel DSL.

UiDslParser extends BuilderSupport{
   
      protected void setParent(Object parent, Object child) {
           if(parent instanceof Container){
               parent.add(child)
               child.parent = parent
           }
       }

       protected Object createNode(Object name) {
           def builder = builderRegistry.getBuilder(name)

           if(builder != null){
                def obj =  builder.build(null, null)

                return obj
           }

           return null 
       }

      //should not come here for Our DSL
       protected Object createNode(Object name, Object value) {

           return null
       }

       protected Object createNode(Object name, Map map) {
           def builder = builderRegistry.getBuilder(name)

           if(builder != null){
                def obj =  builder.build(map, null)                return obj
           }  

           return null
       }

       protected Object createNode(Object name, Map map, Object value) {
           def builder = builderRegistry.getBuilder(name)

           if(builder != null){
                def obj =  builder.build(map, (Closure)value)

               return obj
           }  

          return null
       }

       protected void nodeCompleted(Object parent, Object node) {
      //when the node is completed and its parent is null, it means this node is at the top level
          if(parent == null){
               UiObject uo = (UiObject)node
               //only put the top level nodes into the registry
               registry.put(uo.uid, node)
          }

       }

   }

2) Dynamic Scripting

In Groovy, you can define Groovy code as a String and then run them at run time, i.e, code generates code, which makes pure DSL tests possible. Our DslScriptExecutor? is a good example and can demonstrate the power of the dynamic scripting.

class DslScriptExecutor {

    static void main(String[] args){
       if(args != null &amp;&amp; args.length == 1){
            def dsl = new File(args[0]).text
            def script = &quot;&quot;&quot;
                import aost.dsl.DslScriptEngine

                class DslTest extends DslScriptEngine{
                    def test(){
                        init()
                        ${dsl}
                        shutDown()
                    }
                }

                DslTest instance = new DslTest()
                instance.test()
            &quot;&quot;&quot;

            new GroovyShell().evaluate(script)

       }else{
           println(&quot;Usage: DslScriptExecutor dsl_file&quot;)
       }

    }
}

3) GroovyInterceptable

GroovyInterceptable can intercept all method calls so that you can do some processing before or after the invocation. Or you can delegate the method calls to another class.

For example, The AOST dispatcher will delegate all method calls it received to Selenium Client as follows,

class Dispatcher implements GroovyInterceptable{

    private SeleniumClient sc  = new SeleniumClient()
   
    def invokeMethod(String name, args)
      {
         return sc.client.metaClass.invokeMethod(sc.client, name, args)
      }
}

4) methodMissing

In Groovy, you can use &quot;methodMissing&quot; to intercept and delegate undefined method calls. For example, in DslScriptEngine?, the &quot;methodMissing&quot; method will catch and delegate all methods to DslAostSeleneseTestCase? except the &quot;init&quot;, &quot;openUrl&quot;, and &quot;shutDown&quot; methods:

class DslScriptEngine extends DslContext{

    protected def methodMissing(String name, args) {
         if(name == &quot;init&quot;)
            return init()
         if(name == &quot;openUrl&quot;)
            return openUrl(args)
         if(name == &quot;shutDown&quot;)
            return shutDown()
        
         if(DslAostSeleneseTestCase.metaClass.respondsTo(aost, name, args)){
              return aost.invokeMethod(name, args)
         }

        throw new MissingMethodException(name, DslScriptEngine.class, args)
     }
}

5) Singleton

You can Use Groovy MetaClass to define a singleton, which is the right Groovy way to define a singleton. For example, we have the EventHandler class

class EventHandler{
}

Then, we can define its MetaClass as follows,

class EventHandlerMetaClass extends MetaClassImpl{

    private final static INSTANCE = new EventHandler()

    EventHandlerMetaClass() { super(EventHandler) }

    def invokeConstructor(Object[] arguments) { return INSTANCE }
}

After that, we register the metaClass:

def registry = GroovySystem.metaClassRegistry
registry.setMetaClass(EventHandler, new EventHandlerMetaClass())

In this way, all

Eventhandler handler = new EventHandler()

will return the same Instance, i.e., it is a singleton. Our AOST framework heavily depends on this pattern so that we do not need to use another framework to wiring different object together.

5) GString

GString can be used to embed variable in a String and the value will be resolved at run time. This makes it very convenient to write XPath template. For example, In the Selector object, we have

class Selector extends UiObject {

    def selectByLabel(String target, Closure c){
        c(locator, &quot;label=${target}&quot;)
    }

    def selectByValue(String target, Closure c){

        c(locator, &quot;value=${target}&quot;)()
    }
}

6) Optional Type

In Groovy you can specify a variable type if you know the type and you want to do Type check at compile time. If you do not care about the type or want the method to be more flexible, you do not need to define the type and just use &quot;def&quot; to define a variable without specifying its type.

For example, in the composite locator class we specified the Type of all variables except the position. Because type of UI component position might be a single type.

class CompositeLocator {
    String header
    String tag
    String text
    String trailer
    def position
    Map attributes = [:]
}

7) Groovy Syntax

In Groovy, the syntax is very expressive, for example, the DslContext? class defines a lot of methods such as:

def doubleClick(String uid){}

and it can be written as

doubleClick uid

and the above is one of the basic DSLs for AOST.

The Map definition is also very expressive and useful. AOST locators use map to define xpath or UI component attributes. For example:

ui.Container(uid: &quot;google_start_page&quot;, clocator: [tag: &quot;td&quot;], group: &quot;true&quot;){
   InputBox(uid: &quot;searchbox&quot;, clocator: [title: &quot;Google Search&quot;])
   SubmitButton(uid: &quot;googlesearch&quot;, clocator: [name: &quot;btnG&quot;, value: &quot;Google Search&quot;])
   SubmitButton(uid: &quot;Imfeelinglucky&quot;, clocator: [value: &quot;I&#039;m Feeling Lucky&quot;])
}</description>
		<content:encoded><![CDATA[<p>Groovy Patterns Used in AOST</p>
<p>In AOST(http://code.google.com/p/aost), we used many Groovy patterns. I like to list some of them as follows,</p>
<p>1) BuildSupport</p>
<p>BuildSupport is very powerful for parsing nested definitions, such as XML markup. In AOST, the buildsupport is used as UI object definition parser and it is one of the bases for our internel DSL.</p>
<p>UiDslParser extends BuilderSupport{</p>
<p>      protected void setParent(Object parent, Object child) {<br />
           if(parent instanceof Container){<br />
               parent.add(child)<br />
               child.parent = parent<br />
           }<br />
       }</p>
<p>       protected Object createNode(Object name) {<br />
           def builder = builderRegistry.getBuilder(name)</p>
<p>           if(builder != null){<br />
                def obj =  builder.build(null, null)</p>
<p>                return obj<br />
           }</p>
<p>           return null<br />
       }</p>
<p>      //should not come here for Our DSL<br />
       protected Object createNode(Object name, Object value) {</p>
<p>           return null<br />
       }</p>
<p>       protected Object createNode(Object name, Map map) {<br />
           def builder = builderRegistry.getBuilder(name)</p>
<p>           if(builder != null){<br />
                def obj =  builder.build(map, null)                return obj<br />
           }  </p>
<p>           return null<br />
       }</p>
<p>       protected Object createNode(Object name, Map map, Object value) {<br />
           def builder = builderRegistry.getBuilder(name)</p>
<p>           if(builder != null){<br />
                def obj =  builder.build(map, (Closure)value)</p>
<p>               return obj<br />
           }  </p>
<p>          return null<br />
       }</p>
<p>       protected void nodeCompleted(Object parent, Object node) {<br />
      //when the node is completed and its parent is null, it means this node is at the top level<br />
          if(parent == null){<br />
               UiObject uo = (UiObject)node<br />
               //only put the top level nodes into the registry<br />
               registry.put(uo.uid, node)<br />
          }</p>
<p>       }</p>
<p>   }</p>
<p>2) Dynamic Scripting</p>
<p>In Groovy, you can define Groovy code as a String and then run them at run time, i.e, code generates code, which makes pure DSL tests possible. Our DslScriptExecutor? is a good example and can demonstrate the power of the dynamic scripting.</p>
<p>class DslScriptExecutor {</p>
<p>    static void main(String[] args){<br />
       if(args != null &amp;&amp; args.length == 1){<br />
            def dsl = new File(args[0]).text<br />
            def script = &#8220;&#8221;"<br />
                import aost.dsl.DslScriptEngine</p>
<p>                class DslTest extends DslScriptEngine{<br />
                    def test(){<br />
                        init()<br />
                        ${dsl}<br />
                        shutDown()<br />
                    }<br />
                }</p>
<p>                DslTest instance = new DslTest()<br />
                instance.test()<br />
            &#8220;&#8221;"</p>
<p>            new GroovyShell().evaluate(script)</p>
<p>       }else{<br />
           println(&#8220;Usage: DslScriptExecutor dsl_file&#8221;)<br />
       }</p>
<p>    }<br />
}</p>
<p>3) GroovyInterceptable</p>
<p>GroovyInterceptable can intercept all method calls so that you can do some processing before or after the invocation. Or you can delegate the method calls to another class.</p>
<p>For example, The AOST dispatcher will delegate all method calls it received to Selenium Client as follows,</p>
<p>class Dispatcher implements GroovyInterceptable{</p>
<p>    private SeleniumClient sc  = new SeleniumClient()</p>
<p>    def invokeMethod(String name, args)<br />
      {<br />
         return sc.client.metaClass.invokeMethod(sc.client, name, args)<br />
      }<br />
}</p>
<p>4) methodMissing</p>
<p>In Groovy, you can use &#8220;methodMissing&#8221; to intercept and delegate undefined method calls. For example, in DslScriptEngine?, the &#8220;methodMissing&#8221; method will catch and delegate all methods to DslAostSeleneseTestCase? except the &#8220;init&#8221;, &#8220;openUrl&#8221;, and &#8220;shutDown&#8221; methods:</p>
<p>class DslScriptEngine extends DslContext{</p>
<p>    protected def methodMissing(String name, args) {<br />
         if(name == &#8220;init&#8221;)<br />
            return init()<br />
         if(name == &#8220;openUrl&#8221;)<br />
            return openUrl(args)<br />
         if(name == &#8220;shutDown&#8221;)<br />
            return shutDown()</p>
<p>         if(DslAostSeleneseTestCase.metaClass.respondsTo(aost, name, args)){<br />
              return aost.invokeMethod(name, args)<br />
         }</p>
<p>        throw new MissingMethodException(name, DslScriptEngine.class, args)<br />
     }<br />
}</p>
<p>5) Singleton</p>
<p>You can Use Groovy MetaClass to define a singleton, which is the right Groovy way to define a singleton. For example, we have the EventHandler class</p>
<p>class EventHandler{<br />
}</p>
<p>Then, we can define its MetaClass as follows,</p>
<p>class EventHandlerMetaClass extends MetaClassImpl{</p>
<p>    private final static INSTANCE = new EventHandler()</p>
<p>    EventHandlerMetaClass() { super(EventHandler) }</p>
<p>    def invokeConstructor(Object[] arguments) { return INSTANCE }<br />
}</p>
<p>After that, we register the metaClass:</p>
<p>def registry = GroovySystem.metaClassRegistry<br />
registry.setMetaClass(EventHandler, new EventHandlerMetaClass())</p>
<p>In this way, all</p>
<p>Eventhandler handler = new EventHandler()</p>
<p>will return the same Instance, i.e., it is a singleton. Our AOST framework heavily depends on this pattern so that we do not need to use another framework to wiring different object together.</p>
<p>5) GString</p>
<p>GString can be used to embed variable in a String and the value will be resolved at run time. This makes it very convenient to write XPath template. For example, In the Selector object, we have</p>
<p>class Selector extends UiObject {</p>
<p>    def selectByLabel(String target, Closure c){<br />
        c(locator, &#8220;label=${target}&#8221;)<br />
    }</p>
<p>    def selectByValue(String target, Closure c){</p>
<p>        c(locator, &#8220;value=${target}&#8221;)()<br />
    }<br />
}</p>
<p>6) Optional Type</p>
<p>In Groovy you can specify a variable type if you know the type and you want to do Type check at compile time. If you do not care about the type or want the method to be more flexible, you do not need to define the type and just use &#8220;def&#8221; to define a variable without specifying its type.</p>
<p>For example, in the composite locator class we specified the Type of all variables except the position. Because type of UI component position might be a single type.</p>
<p>class CompositeLocator {<br />
    String header<br />
    String tag<br />
    String text<br />
    String trailer<br />
    def position<br />
    Map attributes = [:]<br />
}</p>
<p>7) Groovy Syntax</p>
<p>In Groovy, the syntax is very expressive, for example, the DslContext? class defines a lot of methods such as:</p>
<p>def doubleClick(String uid){}</p>
<p>and it can be written as</p>
<p>doubleClick uid</p>
<p>and the above is one of the basic DSLs for AOST.</p>
<p>The Map definition is also very expressive and useful. AOST locators use map to define xpath or UI component attributes. For example:</p>
<p>ui.Container(uid: &#8220;google_start_page&#8221;, clocator: [tag: "td"], group: &#8220;true&#8221;){<br />
   InputBox(uid: &#8220;searchbox&#8221;, clocator: [title: "Google Search"])<br />
   SubmitButton(uid: &#8220;googlesearch&#8221;, clocator: [name: "btnG", value: "Google Search"])<br />
   SubmitButton(uid: &#8220;Imfeelinglucky&#8221;, clocator: [value: "I'm Feeling Lucky"])<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>Comment on The abstract object based Selenium Test framework (AOST) by johnjianfang</title>
		<link>http://johnjianfang.wordpress.com/2008/07/08/the-abstract-object-based-selenium-test-framework-aost/#comment-2</link>
		<dc:creator>johnjianfang</dc:creator>
		<pubDate>Sun, 13 Jul 2008 05:24:12 +0000</pubDate>
		<guid isPermaLink="false">http://johnjianfang.wordpress.com/?p=3#comment-2</guid>
		<description>The 0.3.0 verion is just out, which includes an Object to Locator Mapping framework (OLM),. With that, AOST can automatically generate the UI object locator for you. AOST also implements the group locating concept to utilize a group of UI objects to help locating their locators. The new version also add the composite locator so that user specifies a set of parameters for the object and the actual locator will be derived automatically by AOST. The new version also supports multiple UI modules in a single DslContext.

 

The Group Locating Concept (GLC) concept comes from the simple observation, i.e., it is much easier to locate a collection of UI objects than a single UI object. The reason is multiple UI objects provide more search criteria to help you to locate the UIs. This concept is implemented in AOST. All collection type object, i.e., Container and its extended classes have an option to use the group locating concept.

 

Let&#039;s see the differences between regular locating and group locating. Still take the google start page as an example:

ui.Container(uid: &quot;google_start_page&quot;, clocator: [tag: &quot;td&quot;], group: &quot;true&quot;){
  InputBox(uid: &quot;searchbox&quot;, clocator: [title: &quot;Google Search&quot;])
  SubmitButton(uid: &quot;googlesearch&quot;, clocator: [name: &quot;btnG&quot;, value: &quot;Google Search&quot;])
  SubmitButton(uid: &quot;Imfeelinglucky&quot;, clocator: [value: &quot;I&#039;m Feeling Lucky&quot;])
}

 

Here, clocator stands for composite locator. Without group locating, I can only use the given criteria

tag = &quot;td&quot; 

to find the container locator, i.e.,

I am looking for a td html tag in the DOM

which is quite difficult. If we use the group locating, the Container can use the group information provided by its children. Now, the problem becomes:

  I am looking for a td html tag in the DOM and its children including an input box with
  title &quot;Google Search&quot;, a submit button with name &quot;btnG&quot; and value &quot;Google Search&quot;, and
  another submit button with value &quot;I&#039;m Feeling Lucky&quot;

Woo! I have a lot of information to help me to locate the container. Once the container is found, all its children can be found very easily.

 

The direct result of group locating is that for most case, the information defined in the UI module itself is enough for you to locate all UI objects in that UI module. That is to say, your test code only depends on your own UI module, not its location and its outside. Even we change the UI, the test may still work.

Another advantage is that you may be able to map your JSP, PHP, ASP,..., file directly to the UI module in AOST. This could help developers a lot for writing Selenium tests because they do not need to manually find the locator for an UI object.

 

I added FAQ at:

 

http://code.google.com/p/aost/wiki/FAQ

 

Introduction at

 

http://code.google.com/p/aost/wiki/Introduction

 

and Tutorial at:

 

http://code.google.com/p/aost/wiki/Tutorial</description>
		<content:encoded><![CDATA[<p>The 0.3.0 verion is just out, which includes an Object to Locator Mapping framework (OLM),. With that, AOST can automatically generate the UI object locator for you. AOST also implements the group locating concept to utilize a group of UI objects to help locating their locators. The new version also add the composite locator so that user specifies a set of parameters for the object and the actual locator will be derived automatically by AOST. The new version also supports multiple UI modules in a single DslContext.</p>
<p>The Group Locating Concept (GLC) concept comes from the simple observation, i.e., it is much easier to locate a collection of UI objects than a single UI object. The reason is multiple UI objects provide more search criteria to help you to locate the UIs. This concept is implemented in AOST. All collection type object, i.e., Container and its extended classes have an option to use the group locating concept.</p>
<p>Let&#8217;s see the differences between regular locating and group locating. Still take the google start page as an example:</p>
<p>ui.Container(uid: &#8220;google_start_page&#8221;, clocator: [tag: "td"], group: &#8220;true&#8221;){<br />
  InputBox(uid: &#8220;searchbox&#8221;, clocator: [title: "Google Search"])<br />
  SubmitButton(uid: &#8220;googlesearch&#8221;, clocator: [name: "btnG", value: "Google Search"])<br />
  SubmitButton(uid: &#8220;Imfeelinglucky&#8221;, clocator: [value: "I'm Feeling Lucky"])<br />
}</p>
<p>Here, clocator stands for composite locator. Without group locating, I can only use the given criteria</p>
<p>tag = &#8220;td&#8221; </p>
<p>to find the container locator, i.e.,</p>
<p>I am looking for a td html tag in the DOM</p>
<p>which is quite difficult. If we use the group locating, the Container can use the group information provided by its children. Now, the problem becomes:</p>
<p>  I am looking for a td html tag in the DOM and its children including an input box with<br />
  title &#8220;Google Search&#8221;, a submit button with name &#8220;btnG&#8221; and value &#8220;Google Search&#8221;, and<br />
  another submit button with value &#8220;I&#8217;m Feeling Lucky&#8221;</p>
<p>Woo! I have a lot of information to help me to locate the container. Once the container is found, all its children can be found very easily.</p>
<p>The direct result of group locating is that for most case, the information defined in the UI module itself is enough for you to locate all UI objects in that UI module. That is to say, your test code only depends on your own UI module, not its location and its outside. Even we change the UI, the test may still work.</p>
<p>Another advantage is that you may be able to map your JSP, PHP, ASP,&#8230;, file directly to the UI module in AOST. This could help developers a lot for writing Selenium tests because they do not need to manually find the locator for an UI object.</p>
<p>I added FAQ at:</p>
<p><a href="http://code.google.com/p/aost/wiki/FAQ" rel="nofollow">http://code.google.com/p/aost/wiki/FAQ</a></p>
<p>Introduction at</p>
<p><a href="http://code.google.com/p/aost/wiki/Introduction" rel="nofollow">http://code.google.com/p/aost/wiki/Introduction</a></p>
<p>and Tutorial at:</p>
<p><a href="http://code.google.com/p/aost/wiki/Tutorial" rel="nofollow">http://code.google.com/p/aost/wiki/Tutorial</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>Comment on Hello world! by Mr WordPress</title>
		<link>http://johnjianfang.wordpress.com/2008/07/08/hello-world/#comment-1</link>
		<dc:creator>Mr WordPress</dc:creator>
		<pubDate>Tue, 08 Jul 2008 01:15:44 +0000</pubDate>
		<guid isPermaLink="false">#comment-1</guid>
		<description>Hi, this is a comment.&lt;br /&gt;To delete a comment, just log in, and view the posts&#039; comments, there you will have the option to edit or delete them.</description>
		<content:encoded><![CDATA[<p>Hi, this is a comment.<br />To delete a comment, just log in, and view the posts&#8217; comments, there you will have the option to edit or delete them.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
