Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » SWTBot » Unable to get columns in a table
Unable to get columns in a table [message #504460] Sat, 19 December 2009 16:01 Go to next message
Xavier Coulon is currently offline Xavier CoulonFriend
Messages: 58
Registered: July 2009
Member
Hello,

I'm starting using SWTBot in a testcase to simulate a Project Facet activation on a WTP/Java Project.

Although I understood that the 'bot' is like a human-being that sometimes needs to wait (using conditions) before clicking on widgets, I'm stuck on the following issue :
the bot opens the "Project explorer" view, selects the first java project in the view, open the 'Properties' dialog and selects the "Project Facets" property page.
On that page, there's 1 table that (should) contains 3 columns: the first one, without any header label, contains checkboxes to activate/desactivate project facets, the second one contains a label describing the facet and the third and last one contains a combo.

My test case fails on a basic assertion : checking that the table contains 3 columns. The bot just found none, even when I add an (ugly) Thread.sleep(10000);

Here's the code :
		// ensure the "Window" menu is available
		bot.waitUntil(new DefaultCondition() {
			public boolean test() throws Exception {
				return bot.menu("Window").widget != null;
			}

			public String getFailureMessage() {
				return "Widget is not ready!";
			}
		});

		bot.menu("Window").menu("Show View").menu("Project Explorer").click();
		bot.viewByTitle("Project Explorer").setFocus();
		bot.sleep(2000);
		// Select your project in tree view and expand it.
		SWTBotTree tree = bot.viewByTitle("Project Explorer").bot().tree();

		SWTBotTreeItem[] array = tree.getAllItems();
		// There has to be at least one project in the tree view
		Assert.assertEquals("Wrong number of projects in the workspace", 1, array.length);
		Assert.assertEquals("Wrong project name", "test", array[0].getText());
		tree.select("test").expandNode("test");
		bot.menu("Properties").click();
		// moves to the properties dailog box
		SWTBotShell shell = bot.shell("Properties for test");
		shell.activate();
		bot.tree().getTreeItem("Project Facets").select();
		bot.waitUntil(new DefaultCondition() {
			public boolean test() throws Exception {
				return bot.table().widget != null;
			}

			public String getFailureMessage() {
				return "Widget is not ready!";
			}
		});

		bot.table().setFocus();
		Assert.assertTrue("Table not displayed", bot.table().isActive());

		// Get access to the underlying table
		final List<Table> controls = new ChildrenControlFinder(bot.activeShell().widget).findControls(WidgetOfType
				.widgetOfType(Table.class));
		Assert.assertEquals("1 and only 1 table was expected", 1, controls.size());
		// try with ugly delay...
		Thread.sleep(10000);
		// Using the underlying table, select an item
		Assert.assertEquals("Wrong number of columns", 3, bot.table().columnCount()); // FAILS HERE: columnCount() returns '0'




During test execution, I can see all the project facets in the table... but not the Bot Sad
It seems like the call to the widget is performed too quickly, before the table is populated.
Is there any sync condition to add before the last assertion or anything else I should do ?

BTW, comments/review on how to better use SWTBot are welcome !

Thank you in advance
Regards,
Xavier
Re: Unable to get columns in a table [message #504547 is a reply to message #504460] Mon, 21 December 2009 12:50 Go to previous messageGo to next message
Pascal G is currently offline Pascal GFriend
Messages: 157
Registered: July 2009
Senior Member
Xavier Coulon wrote:
> Here's the code :
>
> // ensure the "Window" menu is available
> bot.waitUntil(new DefaultCondition() {
> public boolean test() throws Exception {
> return bot.menu("Window").widget != null;
> }
>
> public String getFailureMessage() {
> return "Widget is not ready!";
> }
> });
>
> bot.menu("Window").menu("Show View").menu("Project
> Explorer").click();
> bot.viewByTitle("Project Explorer").setFocus();
> bot.sleep(2000);
> // Select your project in tree view and expand it.
> SWTBotTree tree = bot.viewByTitle("Project Explorer").bot().tree();
>
> SWTBotTreeItem[] array = tree.getAllItems();
> // There has to be at least one project in the tree view
> Assert.assertEquals("Wrong number of projects in the workspace",
> 1, array.length);
> Assert.assertEquals("Wrong project name", "test",
> array[0].getText());
> tree.select("test").expandNode("test");
> bot.menu("Properties").click();
> // moves to the properties dailog box
> SWTBotShell shell = bot.shell("Properties for test");
> shell.activate();
> bot.tree().getTreeItem("Project Facets").select();
> bot.waitUntil(new DefaultCondition() {
> public boolean test() throws Exception {
> return bot.table().widget != null;
> }
>
> public String getFailureMessage() {
> return "Widget is not ready!";
> }
> });
>
> bot.table().setFocus();
> Assert.assertTrue("Table not displayed", bot.table().isActive());
>
> // Get access to the underlying table
> final List<Table> controls = new
> ChildrenControlFinder(bot.activeShell().widget).findControls (WidgetOfType
> .widgetOfType(Table.class));
> Assert.assertEquals("1 and only 1 table was expected", 1,
> controls.size());
> // try with ugly delay...
> Thread.sleep(10000);
> // Using the underlying table, select an item
> Assert.assertEquals("Wrong number of columns", 3,
> bot.table().columnCount()); // FAILS HERE: columnCount() returns '0'
>
>

You should probably try to fix your testing code first. Lots of thing
you are doing aren't necessary. For example, you don't need a condition
that checks if a widget is null. When you call a method on the bot
(bot.table() for example), it is guaranteed that the returned item will
be "ready" for use. Otherwise, you'll get a WidgetNotFoundException.
Also, you want to avoid as much as possible the bot.sleep() (or
Thread.sleep(), it's the same thing) method; it's a last resort method.
Finally, when I'm writing test code I assume I get the good widget to
not clobbers the code and make it easier to understand for someone else.
With all this applied to your code, you'll get (I deleted some part and
commented others, to help you understand):

bot.menu("Window").menu("Show View").menu("Project Explorer").click();
bot.viewByTitle("Project Explorer").setFocus();
// bot.sleep(2000) You don't need that here, since setFocus() is a
blocking call.

// Select your project in tree view and expand it.
SWTBotTree tree = bot.viewByTitle("Project Explorer").bot().tree();
SWTBotTreeItem[] array = tree.getAllItems();

// There has to be at least one project in the tree view
// Assert.assertEquals("Wrong number of projects in the workspace", 1,
array.length); I wouldn't check for this. Instead, I would have a
setUp() method that creates the required fixture for the test (like your
test project) and a tearDown() method that would delete the fixture.
This way, you'll get much more robust and less inter-dependent tests.

// Assert.assertEquals("Wrong project name", "test",
array[0].getText()); I wouldn't check for this either, since the next
line does. The less code you write, the better

tree.select("test").expandNode("test");
bot.menu("Properties").click();

// moves to the properties dailog box
SWTBotShell shell = bot.shell("Properties for test");
shell.activate();
bot.tree().getTreeItem("Project Facets").select();

bot.table().setFocus();

// try with ugly delay...
// Thread.sleep(10000); Use bot.sleep() instead if you want to wait.
bot.sleep(10000);

// Using the underlying table, select an item
Assert.assertEquals("Wrong number of columns", 3,
bot.table().columnCount()); // FAILS HERE: columnCount() returns '0'


Now, for the real problem: are you sure that the bot finds the good
table? It might find a table that is somewhere else or it might even get
a reference to a table that got hidden so it ends up having 0 columns.
But still, 0 column is weird for a table... Something I would try is:

SWTBotTable table = new
SWTBotTable(bot.widget(widgetOfType(Table.class), shell));
System.err.println(table.getText());
Assert.assertEquals("Wrong number of columns", 3,
bot.table().columnCount());


Hope this helps.
--
Pascal Gélinas | Software Developer
*Nu Echo Inc.*
http://www.nuecho.com/ | http://blog.nuecho.com/

*Because performance matters.*
Re: Unable to get columns in a table [message #504646 is a reply to message #504547] Mon, 21 December 2009 21:00 Go to previous messageGo to next message
Ketan Padegaonkar is currently offline Ketan PadegaonkarFriend
Messages: 873
Registered: July 2009
Senior Member
That's an awesome summary, thanks!

I think there should be a wiki page around some swtbot best practices,
and this seems like a good first candidate for it.

Cheers!

-- Ketan

On 12/21/09 4:50 AM, Pascal Gelinas wrote:
> Xavier Coulon wrote:
>> Here's the code :
>>
>> // ensure the "Window" menu is available
>> bot.waitUntil(new DefaultCondition() {
>> public boolean test() throws Exception {
>> return bot.menu("Window").widget != null;
>> }
>>
>> public String getFailureMessage() {
>> return "Widget is not ready!";
>> }
>> });
>>
>> bot.menu("Window").menu("Show View").menu("Project Explorer").click();
>> bot.viewByTitle("Project Explorer").setFocus();
>> bot.sleep(2000);
>> // Select your project in tree view and expand it.
>> SWTBotTree tree = bot.viewByTitle("Project Explorer").bot().tree();
>>
>> SWTBotTreeItem[] array = tree.getAllItems();
>> // There has to be at least one project in the tree view
>> Assert.assertEquals("Wrong number of projects in the workspace", 1,
>> array.length);
>> Assert.assertEquals("Wrong project name", "test", array[0].getText());
>> tree.select("test").expandNode("test");
>> bot.menu("Properties").click();
>> // moves to the properties dailog box
>> SWTBotShell shell = bot.shell("Properties for test");
>> shell.activate();
>> bot.tree().getTreeItem("Project Facets").select();
>> bot.waitUntil(new DefaultCondition() {
>> public boolean test() throws Exception {
>> return bot.table().widget != null;
>> }
>>
>> public String getFailureMessage() {
>> return "Widget is not ready!";
>> }
>> });
>>
>> bot.table().setFocus();
>> Assert.assertTrue("Table not displayed", bot.table().isActive());
>>
>> // Get access to the underlying table
>> final List<Table> controls = new
>> ChildrenControlFinder(bot.activeShell().widget).findControls (WidgetOfType
>> .widgetOfType(Table.class));
>> Assert.assertEquals("1 and only 1 table was expected", 1,
>> controls.size());
>> // try with ugly delay...
>> Thread.sleep(10000);
>> // Using the underlying table, select an item
>> Assert.assertEquals("Wrong number of columns", 3,
>> bot.table().columnCount()); // FAILS HERE: columnCount() returns '0'
>>
>>
>
> You should probably try to fix your testing code first. Lots of thing
> you are doing aren't necessary. For example, you don't need a condition
> that checks if a widget is null. When you call a method on the bot
> (bot.table() for example), it is guaranteed that the returned item will
> be "ready" for use. Otherwise, you'll get a WidgetNotFoundException.
> Also, you want to avoid as much as possible the bot.sleep() (or
> Thread.sleep(), it's the same thing) method; it's a last resort method.
> Finally, when I'm writing test code I assume I get the good widget to
> not clobbers the code and make it easier to understand for someone else.
> With all this applied to your code, you'll get (I deleted some part and
> commented others, to help you understand):
>
> bot.menu("Window").menu("Show View").menu("Project Explorer").click();
> bot.viewByTitle("Project Explorer").setFocus();
> // bot.sleep(2000) You don't need that here, since setFocus() is a
> blocking call.
>
> // Select your project in tree view and expand it.
> SWTBotTree tree = bot.viewByTitle("Project Explorer").bot().tree();
> SWTBotTreeItem[] array = tree.getAllItems();
>
> // There has to be at least one project in the tree view
> // Assert.assertEquals("Wrong number of projects in the workspace", 1,
> array.length); I wouldn't check for this. Instead, I would have a
> setUp() method that creates the required fixture for the test (like your
> test project) and a tearDown() method that would delete the fixture.
> This way, you'll get much more robust and less inter-dependent tests.
>
> // Assert.assertEquals("Wrong project name", "test",
> array[0].getText()); I wouldn't check for this either, since the next
> line does. The less code you write, the better
>
> tree.select("test").expandNode("test");
> bot.menu("Properties").click();
>
> // moves to the properties dailog box
> SWTBotShell shell = bot.shell("Properties for test");
> shell.activate();
> bot.tree().getTreeItem("Project Facets").select();
>
> bot.table().setFocus();
>
> // try with ugly delay...
> // Thread.sleep(10000); Use bot.sleep() instead if you want to wait.
> bot.sleep(10000);
>
> // Using the underlying table, select an item
> Assert.assertEquals("Wrong number of columns", 3,
> bot.table().columnCount()); // FAILS HERE: columnCount() returns '0'
>
>
> Now, for the real problem: are you sure that the bot finds the good
> table? It might find a table that is somewhere else or it might even get
> a reference to a table that got hidden so it ends up having 0 columns.
> But still, 0 column is weird for a table... Something I would try is:
>
> SWTBotTable table = new
> SWTBotTable(bot.widget(widgetOfType(Table.class), shell));
> System.err.println(table.getText());
> Assert.assertEquals("Wrong number of columns", 3,
> bot.table().columnCount());
>
>
> Hope this helps.
Re: Unable to get columns in a table [message #504656 is a reply to message #504547] Mon, 21 December 2009 22:28 Go to previous messageGo to next message
Xavier Coulon is currently offline Xavier CoulonFriend
Messages: 58
Registered: July 2009
Member
Pascal,

Thank you for your reply, and thank you for your advices, too.
I removed the unnecessary code here and there (some old assertions I added when i started working with SWTBot). I also forgot to mention that the @Before method does all the setup required for CI builds, including the test project creation.

Still, the problem occurs : the 'bot' finds the table on the "Project Facets" property page of my Dynamic Web test project (WTP), but the getColumnCount() returns '0'.

Here's the code I have now :
		SWTBotShell shell = bot.shell("Properties for tapestry5-sample");
		shell.activate();
		bot.tree().getTreeItem("Project Facets").select();
		bot.waitUntil(new DefaultCondition() {
			public boolean test() throws Exception {
				return bot.table().widget != null;
			}

			public String getFailureMessage() {
				return "Widget is not ready!";
			}
		});

		bot.table().setFocus();

		SWTBotTable table = new SWTBotTable(bot.widget(widgetOfType(Table.class), shell.widget));
		Assert.assertEquals("Wrong number of columns", 3, table.columnCount());




I tried to put a breakpoint on the last line (in debug mode) : rowCount() and columnCount() both return 0. Any method on the underlying widget throws an "Invalid Thread Access" SWTException Sad
Any idea ? I'm really stuck on this issue for now...

Thank you in advance

Regards,
Xavier
Re: Unable to get columns in a table [message #504781 is a reply to message #504656] Tue, 22 December 2009 16:22 Go to previous message
Pascal G is currently offline Pascal GFriend
Messages: 157
Registered: July 2009
Senior Member
Xavier Coulon wrote:
> I tried to put a breakpoint on the last line (in debug mode) :
> rowCount() and columnCount() both return 0. Any method on the underlying
> widget throws an "Invalid Thread Access" SWTException :(
> Any idea ? I'm really stuck on this issue for now...

To fix the invalid thread access, simply do this:
syncExec(new VoidResult()
{
public void run()
{
Assert.assertEquals("Wrong number of columns", 3,
table.columnCount());
}
});

And put the breakpoint on the assert. You can now see all the underlying
widget fields without the invalid thread access. The thread access
problem is because (you probably already know this) SWTBot runs the test
code in a separate thread of the UI thread. Using the above method (or
asyncExec()), the run() method is called in the UI thread, so you can
access you widgets data. This helps a lot for debugging.

Now, for your table problem. Let's see if you find the good widget:
change the bot.widget(...) for bot.widgets(...) (keep the same
parameters). This will return you a list of matched widget; look at this
list if it contains the widget you need. If there's only one table,
there might be a bug in the application. Can you see the test run and
assert with your eyes that there is indeed columns in your table? If
there's more then one table, print yourself a trace to the console: the
table index in the list, its column count, the result of getText(), its
row count, etc. This should help you diagnose the problem.

You could also try something else, but it requires access to the
application code. Find your table widget in the code and add this:

table.setData("MyKey", "MyTable");

Now, in the test code, instead of searching for bot.table() or
bot.widget(...), you can now try this:

Matcher<Table> withId = withId("MyKey", "MyTable");
Table table = getBot().widget(allOf(widgetOfType(Table.class), withId));

With this, you can be 100% sure it'll get the good table. If it still
has 0 table, then there might be a bug in your application code.

Hope this helps.
--
Pascal Gélinas | Software Developer
*Nu Echo Inc.*
http://www.nuecho.com/ | http://blog.nuecho.com/

*Because performance matters.*
Previous Topic:Problem while exporting plugin for headless execution
Next Topic:How to deselect/unselect a tree item
Goto Forum:
  


Current Time: Thu Dec 18 22:36:25 GMT 2014

Powered by FUDForum. Page generated in 0.09134 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software