How to properly declare class variables (CUIT Controls)

Viewed 68

I am setting up Coded UI Tests for WPF application and I want to use code approach instead of record-and-generate-code approach. I'd like to use page objects trough code and I need to declare control (buttons, tabs, etc.) variables in page objects that would be used by multiple functions.

I tried declaring the variable in a class and adding properties in constructor (pendingButton1) and creating function which returns the control and assigning to a variable in a class (pendingButton2) but neither worked.

It works when I declare the variable (or create the variable by function) within the function that I want to use the variable in (pendingButton3 and 4).

public partial class Press : Header
{
    WpfToggleButton pendingButton1 = new WpfToggleButton(_wpfWindow);
    WpfToggleButton pendingButton2 = Controls.Press.getPendingButton(_wpfWindow);

    public Press(WpfWindow wpfWindow):base(wpfWindow)
    {
        this.pendingButton1.SearchProperties[WpfControl.PropertyNames.AutomationId] = "Tab1Button";
    }

    public void clickPendingButton() {
        WpfToggleButton pendingButton3 = new WpfToggleButton(_wpfWindow);
        pendingButton3.SearchProperties[WpfControl.PropertyNames.AutomationId] = "Tab1Button";

        WpfToggleButton pendingButton4 = Controls.Press.getPendingButton(_wpfWindow);

        Mouse.Click(pendingButton1); //UITestControlNotFoundException
        Mouse.Click(pendingButton2); //UITestControlNotFoundException
        Mouse.Click(pendingButton3); //This works
        Mouse.Click(pendingButton4); //This works
    }
}

I'd like to make it work when I declare the pendingButton outside clickPendingButton() function since it is used in multiple other functions.

2 Answers

The helper function Controls.getWpfButton() return just properties of the button, not "real" button. It has to be used in a constructor, then it can be used anywhere within the class. I wouldn't say its best practice but it works for me.

Press.cs

public partial class Press : SharedElements
    {
        private WpfButton pendingButton;

    public Press(WpfWindow wpfWindow):base(wpfWindow)
        {
            pendingTab = Controls.getWpfButton(_wpfWindow, "Tab1Button");
        }

    public void clickPendingButton() {
        Mouse.Click(pendingButton);
    }
}

Controls.cs

internal static WpfButton getWpfButton(WpfWindow wpfWindow, string AutomationId)
    {
        WpfButton button = new WpfButton(wpfWindow);
        button.SearchProperties[WpfControl.PropertyNames.AutomationId] = AutomationId;
        return button;
    }

What you want appears to be exactly the sort f code that the Coded UI record and generate tool generates. It creates many pieces of code that have a structure of the following style:

public WpfToggleButton PendingButton
{
    get
    {
        if ((this.mPendingButton == null))
        {
            this.mPendingButton = new WpfToggleButton( ... as needed ...);
            this.mPendingButton.SearchProperties[ ... as needed ...] = ... as needed ...;
        }

        return this.mPendingButton;
    }
}

private WpfToggleButton mPendingButton;

This code declares the button as the class property PendingButton with a private supporting field that has an initial and default value of null. The first time that property is needed the get code executes the required search and saves the found control in the private field. That value is then returned in each subsequent usage of the property. Note that assigning null to the supporting field can be done to cause a new search, as demonstrated in this Q&A.

Related