1

This is Windows 10 UI automation testing via nunit3.ConsoleRunner.

It is really pretty weird, but the same code that worked flawlessly before my vacation now hangs for so far up to 2 hours or more. I created my own MenuClick() method for our tests because the standard MenuBar.MenuItem() method frequently hung as well when navigating past 2nd level menu items. My method worked fine before my vacation, as I said.

Anyway, now, the Menu.SubMenu() call frequently takes 2 hours or more to complete, which is unacceptable.

An additional bit of weirdness is that the test code clicks 3rd level menuitems in pairs, where they both open a Browse For Folder dialog. The first to select a source folder and the other to select a destination folder. The "hang" ONLY occurs (so far) when attempting to get the 2nd level submenu for the second in the pair of 3rd level menuitem clicks.

To get around this currently, I'm spawning a new thread that invokes menu = menuBar.MenuItem(). In the main thread, I wait for menu to be non-null or for timeout to occur before proceeding with a 500 ms sleep between checks. That at least allows me to retry. However, it is appearing that, when this condition occurs, the rest of the menu operations in the entire application under test are hung, so I'm unable to retry. Seems like a bug in the TestStack.White menu handling area.

    public static void GetSubMenu(object obj)
{
    string[] menuNames = obj as string[];
    menu = menuBar.MenuItem(menuNames);
}

private static MenuBar menuBar = null;
private static Menu menu = null;

public static int ClickMenu(MenuBar mainMenu, params string[] menuItems)
{
    menuBar = mainMenu;
    bool bDone = false;
    menu = null;

    System.Threading.Thread t = new System.Threading.Thread(GetSubMenu);
    t.Start(menuItems);
    System.Threading.Thread.Sleep(500);

    DateTime timeOut = DateTime.Now + TimeSpan.FromSeconds(10);

    while (menu == null && DateTime.Now < timeOut)
    {
        System.Threading.Thread.Sleep(500);
    }

    if (menu != null)
    {
        menu.Click();
        bDone = true;
        log.Info($"ClickMenu success");
    }

    t.Abort();

    return bDone ? 1 : 2;
}
Jeff H
  • 157
  • 11
  • Do you really want to set menu = menu.SubMenu(...). Or do you want something like "var item = menu.SubMenu(…); … item.Click();" – StefanG Jan 07 '19 at 18:54
  • Hi, StefanG. Yes, from a pure best practices standpoint, I should use var. But that won't change my problem, will it? I may be missing something? – Jeff H Jan 08 '19 at 18:16
  • What I ment is that you set the result of SubMenu to a new variable. Don't know the implementation details of SubMenu() but this could be an issue. – StefanG Jan 08 '19 at 18:59
  • SubMenu() returns a Menu object, which is why I get the Menu object result and invoke the Click() method on it. In any case, it returns virtually right away MOST of the time, but when it doesn't, it takes up to 2 hours to return. – Jeff H Jan 08 '19 at 21:09

1 Answers1

1

OK, I've determined that the TestStack.White menu operations are susceptible to system busy state, where the thread that is trying to perform the operations doesn't get enough time slices to work, so can take a VERY, VERY long time.

Setting the worker thread priority to ThreadPriority.Highest is key in how I implemented my test suite ClickMenu() method as follows:

public static class Util
{
    static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    private static MenuBar menuBar = null;

    public static void MenuItem(object obj)
    {
        string[] path = obj as string[];

        menuBar.MenuItem(path).Click();
    }

    public static void ClickMenu(MenuBar mainMenu, params string[] menuItems)
    {
        menuBar = mainMenu;

        System.Threading.Thread t = new System.Threading.Thread(MenuItem);
        t.Priority = System.Threading.ThreadPriority.Highest;
        t.Start(menuItems);

        DateTime startTime = DateTime.Now;

        while (t.IsAlive)
        {
            System.Threading.Thread.Sleep(100);
        }

        DateTime endTime = DateTime.Now;
        TimeSpan duration = endTime - startTime;

        if (duration.Seconds > 60)
        {
            log.Info($"Menu Operation duration = {duration.Seconds} sec");
        }
    }
}
Jeff H
  • 157
  • 11