Revision: 3945
Author: pekka.klarck
Date: Thu Aug 26 09:03:45 2010
Log: Explain different approaches how to extend libraries. Work in progress. Issue 626.
http://code.google.com/p/robotframework/source/detail?r=3945

Modified:
 /trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt

=======================================
--- /trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt Tue Jun 8 16:40:06 2010 +++ /trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt Thu Aug 26 09:03:45 2010
@@ -1442,3 +1442,152 @@
 easier to decide which can be used and how they should be used. If you
 are unsure is using some API safe, please send a question to either
 user or developer `mailing list`_.
+
+Extending existing test libraries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section explains different approaches how to add new
+functionality to existing test libraries and how to use them in your
+own libraries otherwise.
+
+Modifying original source code
+''''''''''''''''''''''''''''''
+
+If you have access to the source code of the library you want to
+extend, you can naturally modify the source code directly. The biggest
+problem of this approach is that it can be hard for you to update the
+original library without affecting your changes. For users it may also
+be confusing to use a library that has different functionality than
+the original one. Repackaging the library may also be a big extra
+task.
+
+This approach works extremely well if the enhancements are generic and
+you plan to submit them back to the original developers. If your
+changes are applied to the original library, they are included in the
+future releases and all the problems discussed above are mitigated. If
+changes are non-generic, or you for some other reason cannot submit
+them back, the approaches explained in the subsequent sections
+probably work better.
+
+Using inheritance
+'''''''''''''''''
+
+Another straightforward way to extend an existing library is using
+inheritance. This is illustrated by the example below that adds new
+:name:`Title Should Start With` keyword to the SeleniumLibrary_. This
+example uses Python, but you can obviously extend an existing Java
+library in Java code the same way.
+
+.. sourcecode:: python
+
+   from SeleniumLibrary import SeleniumLibrary
+
+   class ExtendedSeleniumLibrary(SeleniumLibrary):
+
+       def title_should_start_with(self, expected):
+                  title = self.get_title()
+           if not title.startswith(expected):
+               raise AssertionError("Title '%s' did not start with '%s'"
+                                    % (title, expected))
+
+.. Note:: The new keyword added in this particular example is generic
+          and should be added to the original library instead. In
+          practice it is so simple that it can created as a `user
+          keyword`_ and is unlikely to be added.
+
+A big difference with this approach compared to modifying the original
+library is that the new library has a different name than the
+original. A benefit is that you can easily tell that you are using a
+custom library, but a big problem is that you cannot easily use the
+new library with the original. First of all your new library will have
+same keywords as the original meaning that there is always
+conflict__. Another problem is that the libraries do not share their
+state.
+
+This approach works well when you start to use a new library and want
+to add custom enhancements to it from the beginning. Otherwise other
+mechanisms explained in this section are probably better.
+
+__ `Handling keywords with same names`_
+
+Using delegation
+''''''''''''''''
+
+Because test libraries are technically just classes or modules, a
+simple way to use another library is importing it and using its
+methods. This approach works great when the methods are static and do
+not depend on the library state. This is illustrated by the earlier
+example that uses `Robot Framework's BuiltIn library`__.
+
+If the library has state, however, things may not work as you would
+hope.  The library instance you use in your library will not be the
+same as the framework uses, and thus changes done by executed keywords
+are not visible to your library. The next section explains how to get
+an access to the same library instance that the framework uses.
+
+__ `Using Robot Framework's internal modules`_
+
+Getting active library instance from Robot Framework
+''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Robot Framework 2.5.2 added by BuiltIn_ keyword :name:`Get Library
+Instance` that can be used to get the currently active library
+instance from the framework itself. The library instance returned by
+this keyword is the same as the framework itself uses, and thus
+there is no problem seeing the correct library state. Although this
+functionality is available as a keyword, it is typically used in test
+libraries directly by importing the :name:`BuiltIn` library class `as
+discussed earlier`__. The following example illustrates how to
+implement the same :name:`Title Should Start With` keyword as in the
+earlier example about `using inheritance`_.
+
+__ `Using Robot Framework's internal modules`_
+
+.. sourcecode:: python
+
+   from robot.libraries.BuiltIn import BuiltIn
+
+   def title_should_start_with(expected):
+       seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
+       title = seleniumlib.get_title()
+       if not title.startswith(expected):
+           raise AssertionError("Title '%s' did not start with '%s'"
+                                % (title, expected))
+
+This approach is clearly better than importing the library directly
+and using it when the library has a state. The biggest benefit over
+inheritance is that you can use the original library normally and use
+the new library in addition to it when needed. That is demonstrated in
+the example below where the code from the previous examples is
+expected to be available in a new library :name:`SeLibExtensions`.
+
+.. table:: Using library and another library that extends it
+   :class: example
+
+   ===========  ===============  =======  =======
+    Settings         Value        Value    Value
+   ===========  ===============  =======  =======
+   Library      SeleniumLibrary
+   Library      SeLibExtensions
+   ===========  ===============  =======  =======
+
+.. table::
+   :class: example
+
+ =============== ======================= ============== =================
+      Test Case             Action              Argument          Argument
+ =============== ======================= ============== ================= + Example Open Browser http://example # SeleniumLibrary + \ Title Should Start With Example # SeLibExtensions + =============== ======================= ============== =================
+
+
+Libraries using dynamic or hybrid API
+'''''''''''''''''''''''''''''''''''''
+
+Test libraries that use the dynamic__ or `hybrid library API`_ often
+have their own systems how to extend them. With these libraries you
+need to ask guidance from the library developers or consult the
+library documentation or source code.
+
+__ `dynamic library API`_

Reply via email to