Ich spiele schon seit einiger Zeit mit dieser Idee herum und habe sie in der Vergangenheit bereits für einen Kunden erstellt. Nachdem ich jedoch Fragen von CodedUI-Nutzern erhalten habe, die versucht haben, eine vereinfachte Syntax zu entwickeln, dachte ich, es wäre an der Zeit, das zu veröffentlichen, was ich im Moment habe.
Wenn Sie Ihre Testautomatisierung mit CodedUI von Hand programmieren, dann wissen Sie, dass die Suche nach einem Steuerelement immer ein paar Zeilen Code erfordert, um eine Suche einzurichten. Sie erstellen zunächst eine Instanz des Steuerelements, das Sie benötigen, geben ihm im Konstruktor den Suchbereich und müssen dann die Sucheigenschaften festlegen. Sobald dies geschehen ist, können Sie das Steuerelement verwenden und sobald Sie eine seiner Eigenschaften verwenden, wird es nach Ihrem Steuerelement suchen.
Bei Selenium ist das ein bisschen anders. Sie haben die Klasse Driver, die mehr oder weniger die primären Methoden bereitstellt. FindElement und FindElements zur Verfügung stellt, und Sie übergeben ihr eine Instanz der Klasse By, die die Suchkriterien enthält.
Lassen Sie mich das an zwei Beispielen erläutern. Bot macht das Gleiche. Wir gehen auf die Google-Startseite und geben eine Suchanfrage ein.
CodedUI:
BrowserWindow b = BrowserWindow.Launch(new Uri("https://google.com"));
HtmlEdit searchBox = new HtmlEdit(b);
searchBox.SearchProperties.Add(HtmlEdit.PropertyNames.Id, "lst-ib");
Keyboard.SendKeys(searchBox, "codedUI Kurs{Enter}");Selen:
var driver = new ChromeDriver(@"driverfolder");
driver.Navigate().GoToUrl("https://google.com");
var searchBox = driver.FindElement(By.Id("lst-ib"));
searchBox.SendKeys("codedUI Kurs{Enter}");Im Allgemeinen höre ich, dass die Leute die Selenium-Syntax mehr mögen als den mehrstufigen Ansatz in codedUI. Was mir nicht gefällt, ist, dass ich die Typsicherheit des Typs der Steuerung verliere. Die Frage ist also, ob es möglich wäre, die gleiche Syntax für codedUI zu verwenden und trotzdem codedUI zu nutzen und eine typsichere Art der Interaktion mit den Suchkontrollen zu erhalten?
Die Antwort lautet (natürlich): Ja, das ist möglich, indem Sie ein paar Erweiterungsmethoden und eine raffinierte Implementierung der Klasse By erstellen.
Lassen Sie mich Ihnen also zunächst zeigen, wie das aussieht, wenn Sie die von mir erstellten Erweiterungsmethoden verwenden:
CodedUI mit Selenium-Syntax:
BrowserWindow b = BrowserWindow.Launch(new Uri("https://google.com"));
var searchBox= b.FindElement<HtmlEdit>(By.Id("lst-ib"));
searchBox.SendKeys( "codedUI Kurs{Enter}");Jetzt habe ich also die Typsicherheit, die ich von codedUi gewohnt bin, aber ich habe die etwas knappe Syntax, um Elemente eines bestimmten Typs zu finden.
Wie sieht also diese Erweiterungsmethode aus?
Also habe ich zunächst eine Erweiterungsmethode für UITestControl erstellt, die wie folgt aussieht:
public static T FindElement<T>(dieser UITestControl-Container, Func<UITestControl,HtmlControl,HtmlControl>
controlConstructorFunct) wo T:HtmlControl , new()
{
var control = new T {Container = container};
controlConstructorFunct(container, control);
Rückgabekontrolle ;
}
Die Magie liegt nun darin, dass wir dieser Funktion eine Funktion übergeben, die das gerade instanziierte Steuerelement mit den richtigen Sucheigenschaften initialisieren kann.
Dies ist die Implementierung der By-Klasse, die ich gerade erwähnt habe. Sie sieht wie folgt aus:
public class By
{
public static Func<UITestControl, HtmlControl,HtmlControl> Id(string id)
{
return (container,control) =>
{
control.SearchProperties.Add(HtmlControl.PropertyNames.Id, id); return control;
};
}
}
Jetzt müssen wir dies nur noch für alle Standardarten der Suche nach einem Steuerelement implementieren. Das wäre also nach CSS-Klasse, nach CSS-Abfrage, nach innerText, usw.
Schließlich benötigen wir eine Erweiterungsmethode für UITestControl, um Mausklicks und Tastatureingaben zu verarbeiten. Diese sehen wie folgt aus:
public static void Click(this UITestControl control)
{
Mouse.Click(control);
}
public static void SendKeys(this UITestControl control, string text)
{
Keyboard.SendKeys(control, text);
}Schließlich habe ich auch die Art und Weise, wie wir eine Suche über eine Css-Abfrage durchführen, etwas anders implementiert. Wie ich in früheren Beiträgen beschrieben habe, verwende ich für die Suche nach einem Steuerelement, das z.B. auf benutzerdefinierten Attributen basiert, wie es bei Angular-Seiten der Fall ist, eine Implementierung, die ein Java-Skript aufruft. Dieses gibt dann das Objekt zurück und wir müssen sicherstellen, dass es von dem Typ ist, den wir erwarten. Die einzige Einschränkung ist, dass dies auf einem UITestControl vom Typ BrowserWindow aufgerufen wird. Leider habe ich keine Möglichkeit gefunden, dies im Compiler zu erzwingen, also habe ich dies als Laufzeitprüfung implementiert.
Der Code dafür sieht wie folgt aus:
public static Func<UITestControl, HtmlControl, HtmlControl>
CssSelector(string cssSelectorToFind)
{
const string javascript = "return document.querySelector('{0}');";
var scriptToExecute = string.Format(javascript, cssSelectorToFind);
return (container, control) =>
{
var browserWindow = container as BrowserWindow;
if(browserFenster==null)
neu werfen
ArgumentException("Sie können die Funktion CSSSelector nur für ein Steuerelement vom Typ BrowserWindow verwenden");
var searchControl =
browserWindow.ExecuteScript(scriptToExecute) as HtmlControl;
var foundControltype = searchControl?.GetType();
var returnType = control.GetType();
if (foundControltype?.FullName == returnType.FullName)
{
control = searchControl;
}
sonst
{
throw new InvalidCastException(
$"Das gefundene Steuerelement kann dem Typ {returnType.FullName} nicht zugeordnet werden, das Steuerelement ist vom Typ {foundControltype?.FullName}");
}
Rückgabekontrolle;
};
}Ich habe den endgültigen Code hier auf GitHub veröffentlicht, so dass Sie ihn leicht herunterladen und dazu beitragen können, wenn Sie zusätzliche Erkenntnisse haben.
Was ich geteilt habe, ist nicht vollständig, aber ich teile es lieber jetzt, als darauf zu warten, dass ich die Zeit finde, es fertigzustellen, um die gesamte Selenium-Methode zu unterstützen.
Lassen Sie mich wissen, was Sie denken.
Hoffentlich hilft das!
Verfasst von
Marcel de Vries
Marcel is a key figure in the technology sector, serving as the co-founder and Global MD & CTO of Xebia Microsoft Services. He is deeply involved in advancing organizational capabilities to deploy software swiftly and securely, emphasizing the importance of innovation and productivity while maintaining compliance. Marcel is passionate about technology and continuous learning, often sharing his insights at leading industry events and through online courses on Pluralsight. Recognized for his contributions, Marcel has been honored with the Microsoft MVP award for over 17 consecutive years and is a Microsoft Regional Director since 2008. His expertise spans across Cloud Adoption Strategies, DevOps, and various cloud computing frameworks, making him a respected voice in the tech community.
Contact