Thanks for share your experience!! 2011/6/9 Ed <[email protected]>
> I like to share some testing experience with you, as I am very happy > about it: > > I have a GWT app that contains some complex business rules/logic which > are difficult to test as they are embedded in the View. > This is something that always frustrated me as bugs very difficult to > track. > > Used testing: > 1) I use the MVP(C) pattern everywhere possible and make presenter > tests. > 2) I use a few GWT tests but they always give me problems as I am > running in -noserver mode. > 3) I use Selenium tests for display testing (running all Selenium > tests take more then 30 hours on one machine). > > I tried to extract/put this difficult-to-test embedded business logic > (BL) in to a presenter, but things got very ugly and difficult to > maintain. I found out that MVP is great but not always suitable. > > ## An example of BL that I couldn't test with one of the above > methods: > I have a menu on the left side that show a display on the right side > with text box entries that the user can fill in. The user can add and > remove new entries and erase the content of a line that contains a > collection of entries. > The content of the entries are stored and retrieved from a central > data model. It's retrieved when the display is shown and stored when > the user selects another menu item such that it navigates away from > the current display (not earlier as might want to undo his changes if > they aren't valid for example). > > ## I want to test the following scenario: > Correct storage of the display value in the data model. That sounds > simple but suppose a member erases some entries and removes some > entries and creates a few new ones. You have to register the removed > entries such that they are removed from the data model when the user > selects another menu item (not earlier). > Testing this with Selenium was hard as these details aren't easy made > visible on the screen. Detail: i had to save the data model to the > backend and restart the application such that the display is filled > with the earlier stored data. > However, it's important to test this as bugs are unacceptable in this > part. > > It was bothering me for quite some time now that I couldn't test this > until GWT came out with the IsWidget interface in version 2.1. This > interface is implemented by Widget. It's main use is for View's that > implement IsWidget and can easier be mocked. But it's not really meant > on detail level were I want to use it for. > I was asking for a Widget interface for a long time and finally > IsWidget appeared which was good enough for me... > > ## My Solution to test the above: > The idea: > Let all widgets implement AsWidget instead of extending of Widget and > create the Display widget as late as possible. > With a few exceptions you could say: the actual creation of the > display widget should only occur when it's attached to some panel. > > Changes I made: > In general I never use the GWT panel's directly, but use them trhough > own Panel wrappers such that I can add functionality like insert/ > removal animations (I opened a Feature request about this a long time > ago: 3867) . > I changes the add/insert/remove methods in the Panel wrapper to accept > the IsWidget as type and store the IsWidgets widgets in a private > collection. > The contained GWT panel is only used when GWT.isClient yields true. > Side note: because of this private collection, the panel wrapper > returns the IsWidget instance that was added/inserted when requested > with the method gwtWidget(int) instead as with the GWT panel, that > always return the Widget instead, even if you inserted the IsWidget > object that contains the Widget itself. This is confusing (see > > http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/e7007d4d4098627b > for discussion about this). > > I changed the involved widgets to implement the IsWidget interface and > no longer extend from Widget. > The widget is only created when needed such that the method > IsWidget.asWidget() is called. > The idea is that you embed your view in your presenter (Embedded View > Pattern), see Martin fowler for details about this. > So basically we split up a widget in a Logical and Display widget. > > That's basically it. It's pretty cool to finally be able to unit test > (and fast) Widgets or a collection of Widgets, like a new world opens > up :) > Of course you this isn't some kind of Perfect solution, but perfect > solutions don't exists in general, but you can test a lot more then > before. > > ## Fine tuning: > I fine tuned things a bit: > - A widget will also want to create it self when you set the style, > debug id, etc... on the widget, so you have to fine tune your code > such that it occurs only when the widget is created, or cache these > settings and add them when the widget is created. I choose for the > latter option through a small parent class called SimpleIsWidget that > implements IsWidget that overrides methods like setStyleName, > ensureDebugId, etc.. (add as much as you want). My widgets extends > from SimpleIsWidget and the parent class will cache/buffer style/debug > settings till it's created. It will automatically ask the subclass to > create the display widget when needed or when the method asWidget() is > called. This works pretty well. > > - When listening for an event, the event will contain the display > widget that triggered the event. However we often want the logical > widget that created the display widget to perform additional actions > as the display widget doesn't contain any BL. > Example: class Entry that extends SimpleIsWidget, creates widget > EntryDisplay that extends Widget that is contained in the received > event (like a click event). > I added the interface HasCreator that the created display widget can > implement and will return the Logic widget. As such that the Logical > and Display widgets are associated bidirectional. > > I hope this helps you with your testing. > > I also hope that the GWT dev team will further extend the usage of the > IsWidget interface in the GWT framework such that testing becomes > easier and more testing can be done without the use of the slow > GWTTestCase method. I opened an issue about this some time ago and > hope that developers recognize the need for this and vote the issue > such that the GWT dev team will realize the required changes to gain > better testing. > The issue: 6113 (http://code.google.com/p/google-web-toolkit/issues/ > detail?id=6113) > > - Ed > > -- > You received this message because you are subscribed to the Google Groups > "Google Web Toolkit" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/google-web-toolkit?hl=en. > > -- You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
