I work with Specflow (if there is such a function there)
Programming language C#.
I want a screenshot to be taken after each selenium action.
Why? -> I want that after the first automation, a series of pictures of the successful test run is created (so that business analysts in the future can quickly see via pictures, what is tested with which test caseid).
It should be possible to specify via a flag whether the screenshot should be created or not. So my main problem is:
How do I ensure that my screenshot function is automatically called after each "driver.FindElement.... "and then "variable.click" or similar?
I don't want to manually insert "makeScreenshot()" everywhere.
It would be wonderful if a different method could be called after each method call. That looks up what the "command is". If the syntax then matches something like "Click()", the screenshot is triggered, otherwise not.
If there is no such thing. Something like "Screenshot(variable.Click())" would also be conceivable. That would still be clean and easily implemented everywhere via copy paste.
Does anyone have an idea or a link? (I'm a bit of a noob and need code examples to get started)
Potential solution 1:
You could add a extension method to your project for IWebElement, which would allow you to create your own custom click and find methods that screenshot after clicking. For example:
public static class IWebElementExtensions
{
public static void ClickAndScreenshot(this IWebElement element,
IWebDriver driver,
ScenarioContext scenarioContext)
{
element.Click();
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
ss.SaveAsFile($"{scenarioContext.ScenarioInfo.Title}_{scenarioContext.StepContext.StepInfo.Text.Replace("\"", "")}.png",
ScreenshotImageFormat.Png);
}
}
If you add the above class to your project and reference it in your steps, it would click the element, and then take a screenshot and add the scenario and step info to the filename to identify it later (consider how you plan to manage these screenshots, might be worth adding a subfolder per scenario, or datetimes to the filename for diagnostics).
You can then make use of this method in your Specflow steps:
[When(#"I click a login button")]
public void WhenIClickALoginButton()
{
By someLoginButton = By.Id("login");
_driver.FindElement(someLoginButton).ClickAndScreenshot(_driver, _scenarioContext);
}
You could do something similar for finding the element. You could create an extension method that finds the element, takes a screenshot and then returns the element as a return type to be used by your WebDriver.
You would have to change your current click() methods to take advantage of this new method (find and replace should help make this trivial), but your screenshot code would all be in one place if you need to change it. Doing it this way means you can pick and choose when to call that method as well depending on your steps, as you could stick to the original Click() method if not interested in a screenshot in a particular step.
Potential Solution 2:
I feel like taking a screenshot after every Specflow step rather then each Selenium action is worth mentioning as a potential solution, focusing on chunks of user actions rather then every Selenium action.
For example, you could configure a hooks file to take a screenshot after every specflow step:
[Binding]
public class Hooks
{
IWebDriver _driver;
public Hooks(IWebDriver driver)
{
_driver = driver;
}
[Scope(Tag = "screenshot")]
[AfterStep]
public void TakeScreenshotAfterStep(ScenarioContext scenarioContext)
{
Screenshot screenshot = ((ITakesScreenshot)_driver).GetScreenshot();
screenshot.SaveAsFile($"{scenarioContext.ScenarioInfo.Title}_{scenarioContext.StepContext.StepInfo.Text}.png",
ScreenshotImageFormat.Png);
}
[AfterScenario]
public void AfterScenario()
{
_driver.Dispose();
}
}
For a example Feature:
Feature: Login
#screenshot
Scenario: Successful Login
GIVEN I navigate to stack overflow
WHEN I login
THEN I am logged in
#someOtherTag
Scenario: API test with no UI
GIVEN I have a cool API
WHEN I do a GET
THEN I GET some cool stuff
This would generate 3 screenshots after each step for the Successful login scenario, but it wouldn't take any for the API test due to the tag scope on the after step, which should tick the box around being able to specify when to do this.
The above relies on your Specflow steps not being too large though... if you're doing multiple large chunks of user actions within one step, it may skip a lot, but if that's only a rare occurrence you could do some extra screenshot taking within those steps using the extension from potential solution 1.
I hope this helps, I apprieciate it's not a pure answer but from experience of when these sorts of screenshots can be useful, I'd recommend solution 2 and use it as an opportunity to make sure your Specflow steps aren't doing too much.
Related
I am new to C# and am trying to use SpecFlow as I used to use Gherkin by giving a unique name to an item and then passing in the name in the Step Definition. My question is about how to add in the identifier when I create an object so I can call the object without having to pass in the actual name of the object every time that I create a step.
So, for instance the code would look something like this:
[When(#"I click the (.*) button")]
public void ClickTheButton(string ButtonName)
{
driver.Click(ButtonName)
//ButtonName would be a string that would call to the ID for the ADD button
}
I want to be able to put in something like "Add" (so the line would read "When I click the ADD button") and then have the code search for the "ADD" identifier.
I know that this is possible in Ruby/Cucumber by using a DOM and then passing in XML with gherkin names. In Ruby/Cucumber the object would look something like this:
<button gherkin_name="ADD" key="id" value="add_button_12685"/>
However, I am finding absolutely no way of doing that in C# with SpecFlow and this is something that I really need to be able to do.
Is there a way to do this at all? All I'm really trying to do is link a handle/parameter name that business users could actually use to a Page Object like you can in Ruby/Cucumber without making the user know the code in the background. And, incidentally, the names of the objects are almost exactly like the gherkin line that I added in, thus they are very weird to have a user write. This is the reason that I'd like to have just an identifier for the user.
Thanks in advance for your help.
EDIT: I realise now I was not clear enough in my original post so perhaps some background will help. I am using Selenium-Webdriver to test a website that has hundreds of items on it. Writing a different step for every single item on every single page would be exceedingly tedious and time consuming. Because there are many of the exact same items with the exact same characteristics (for instance there are something like 50 buttons that all behave similarly on a single page and the site is dozens of pages) on the pages, writing a single method for testing them seems the most logical idea. Identifying these items with an identifier that the business could use would cut down on bulk inside of the Steps, the number of steps written, and the likelihood that the business users would feel comfortable using the code which is the end goal.
You can do what you want if you are using the PageObject pattern and have a property Buttons (probably on a base PageObject class) which exposes the available buttons as a collection (which can be done via reflection) and then you can just do something like:
[When(#"I click the (.*) button")]
public void ClickTheButton(string ButtonName)
{
myPage.Buttons.First(button=>button.Name==ButtonName).Click;
}
but I would take what AutomatedChaos said into consideration and not use this in a step in the gerkin but just have this as a helper method something like this
[When(#"I add a widget")]
public void AddAWidget(string ButtonName)
{
ClickTheButton("Add")
}
private void ClickTheButton(string ButtonName)
{
myPage.Buttons.First(button=>button.Name==ButtonName).Click;
}
your Buttons property doesn't have to be done with reflection, the simplest implementation is something like this:
public IEnumerable<IWebElement> Buttons
{
yield return AddButton;
yield return RemoveButton;
yield return SomeOtherButton;
//etc etc
}
but using reflection will mean that as you add buttons to the page object you don't need to remember to add them to this method, they will be found automatically.
SpecFlow is only the BDD framework. It will not drive browsers itself, you need to install additional packages that drives the browser.
With C#, you have a few options:
Selenium, the best known and works with the Page Object you are accustomed with.
Fluent Automation, an upcoming library that works as a wrapper on top of Selenium, and makes the interfacing easier (more natural language)
CodedUI, Microsofts web and UI test solution that comes natively with Visual Studio Test edition.
On a personal note, I consider Selenium (with or without Fluent Automation) the best fitted to work with SpecFlow (comparisson)
If you want to install Selenium or other packages, you can install the NuGet package manager to easily search, install and update packages for you.
Lastly, have you considered to use more domain specific Gherkin phrases like When I add a Wabberjock instead of When I press the Add button? This is where the power of BDD lies: Exposing the intention while hiding the implementation details.
I am learning how to use the Telerik test environment.
I created a test that runs through my program. One of the steps is to create a repository, into which I will upload data. I would like to run this test numerous times as a load test, so the name needs to be dynamic. I would like to create a name such as "Repository_Date_Time, since no matter how many times I use it, uniqueness is guaranteed.
I created a code step right before the text box insertion step. I would like to generate a string, and then use it in the next step so that the repository is created with a unique name.
Code generated is: this is in the steps within the telerik application
[WebTest_CodedStep] : New Coded Step
Then, within this step, I can hard code stuff:
[CodedStep(#"New Coded Step")]
public void WebTest_CodedStep()
{
}
I want to use something like this: string currentTime = DateTime.Now.ToString("HH:mm:ss");
and then use the saveNow contained data as an ending to a string to make it unique, but it must be done within the following step:
Type 'Moshe-Master Repository Test01' into Item0Textboxchanged
TypedText: Moshe-Master Repository Test01
So that the red name will be substituted by a variable carrying the new string which I creatred.
The TypedText box is the value being typed automatically, and I would like to change it with the generated value from the previous step. Can a TypedText value be dynamic?
Thanks!
EDIT: I just realized that therre is a way to use a variable as input, however, I do not know where I can create it. The location where I can put it as input is in the top right state-chart with all current data being used for that particular step. (bindings) is set to collection at the moment. When I try to change it into a variable it tells me that the variable needs to be created- it does not specify where.
I am trying to get started in Visual Studio (2010) extensions and I am having a hard time finding the right materials. I have the SDK, but the included samples seem to be things like adorners, windows, and icons.
I am trying to make an extension that will work directly with the text editor (to alphabetize all of my method names in a class, or make all constant names upper case for example) but I can't find a demo for this type of functionality, or even a tutorial.
Does anyone know where I can find this kind of stuff?
I had the exact same question and now have browsed the web several hours until I was being able to understand and explain how you'd need to start with such an extension.
In my following example we will create a small and dumb extension which will always add "Hello" to the beginning of a code file when an edit has been made. It's very basic but should give you an idea how to continue developing this thing.
Be warned: You have to parse the code files completely on your own - Visual Studio does not give you any information about where classes, methods or whatever are and what they contain. That's the biggest hurdle to be taken when doing a code formatting tool and will not be covered in this answer.[*]
For those who skipped to this answer, make sure you downloaded and installed the Visual Studio SDK first or you will not find the project type mentioned in step one.
Creating the project
Start by creating a new project of the type "Visual C# > Extensibility > VSIX Project" (only visible if you selected .NET Framework 4 as the target framework). Please note that you may have to select the "Editor Classifier" project type instead of the "VSIX Project" type to get it working, s. comment below.
After the project has been created, the "source.extension.vsixmanifest" file will be opened, giving you the ability to set up product name, author, version, description, icon and so on. I think this step is pretty self-explaining, you can close the tab now and restore it later by opening the vsixmanifest file.
Creating a listener class to get notified about text editor instance creations
Next, we need to listen whenever a text editor has been created in Visual Studio and bind our code formatting tool to it. A text editor in VS2010 is an instance of IWpfTextView.
Add a new class to our project and name it TextViewCreationListener. This class has to implement the Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener interface. You need to add a reference to Microsoft.VisualStudio.Text.UI.Wpf to your project. The assembly DLL is found in your Visual Studio SDK directory under VisualStudioIntegration\Common\Assemblies\v4.0.
You have to implement the TextViewCreated method of the interface. This method has a parameter specifying the instance of the text editor which has been created. We will create a new code formatting class which this instance is passed to later on.
We need to make the TextViewCreationListener class visible to Visual Studio by specifying the attribute [Export(typeof(IWpfTextViewCreationListener))]. Add a reference to System.ComponentModel.Composition to your project for the Export attribute.
Additionally, we need to specify with which types of files the code formatter should be bound to the text editor. We only like to format code files and not plain text files, so we add the attribute [ContentType("code")] to the listener class. You have to add a reference to Microsoft.VisualStudio.CoreUtility to your project for this.
Also, we only want to change editable code and not the colors or adornments around it (as seen in the example projects), so we add the attribute [TextViewRole(PredefinedTextViewRoles.Editable)] to the class. Again you need a new reference, this time to Microsoft.VisualStudio.Text.UI.
Mark the class as internal sealed. At least that's my recommendation. Now your class should look similar to this:
[ContentType("code")]
[Export(typeof(IWpfTextViewCreationListener))]
[TextViewRole(PredefinedTextViewRoles.Editable)]
internal sealed class TextViewCreationListener : IWpfTextViewCreationListener
{
public void TextViewCreated(IWpfTextView textView)
{
}
}
Creating a class for code formatting
Next, we need a class handling the code formatting logic, sorting methods and so on. Again, in this example it will simply add "Hello" to the start of the file whenever an edit has been made.
Add a new class called Formatter to your project.
Add a constructor which takes one IWpfTextView argument. Remember that we wanted to pass the created editor instance to this formatting class in the TextViewCreated method of our listener class (simply add new Formatter(textView); to the method there).
Save the passed instance in a member variable. It'll become handy when formatting the code later on (e.g. for retrieving the caret position). Also tie up the Changed and PostChanged events of the TextBuffer property of the editor instance:
public Formatter(IWpfTextView view)
{
_view = view;
_view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
_view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
}
The Changed event is called every time an edit has been made (e.g. typing a char, pasting code or programmatical changes). Because it also reacts on programmatical changes I use a bool determining if our extension or the user / anything else is changing the code at the moment and call my custom FormatCode() method only if our extension is not already editing. Otherwise you'll recursively call this method which would crash Visual Studio:
private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
{
if (!_isChangingText)
{
_isChangingText = true;
FormatCode(e);
}
}
We have to reset this bool member variable in the PostChanged event handler again to false.
Let's pass the event args of the Changed event to our custom FormatCode method because they contain what has changed between the last edit and now. Those edits are stored in the array e.Changes of the type INormalizedTextChangeCollection (s. the link at the end of my post for more information about this type). We loop through all those edits and call our custom HandleChange method with the new text which this edit has produced.
private void FormatCode(TextContentChangedEventArgs e)
{
if (e.Changes != null)
{
for (int i = 0; i < e.Changes.Count; i++)
{
HandleChange(e.Changes[0].NewText);
}
}
}
In the HandleChange method we could actually scan for keywords to handle those in a specific way (remember, you have to parse any code on yourself!) - but here we just dumbly add "Hello" to the start of the file for testing purposes. E.g. we have to change the TextBuffer of our editor instance. To do so, we need to create an ITextEdit object with which we can manipulate text and apply it's changes afterwards. The code is pretty self-explaining:
private void HandleChange(string newText)
{
ITextEdit edit = _view.TextBuffer.CreateEdit();
edit.Insert(0, "Hello");
edit.Apply();
}
When compiling this add-in, an experimental hive of Visual Studio starts up with only our extension loaded. Create a new C# file and start typing to see the results.
I hope this gives you some ideas how to continue in this topic. I have to explore it myself now.
I highly recommend the documentation of the text model of the editor on MSDN to get hints about how you could do this and that.
http://msdn.microsoft.com/en-us/library/dd885240.aspx#textmodel
Footnotes
[*] Note that Visual Studio 2015 or newer come with the Rosyln Compiler Platform, which indeed already analyzes C# and VB.NET files for you (and probably other pre-installed languages too) and exposes their hierarchical syntactical structure, but I'm not an expert in this topic yet to give an answer on how to use these new services. The basic progress of starting an editor extension stays the same as described in this answer anyway. Be aware that - if you use these services - you will become dependent on Visual Studio 2015+, and the extension will not work in earlier versions.
just have a look at the "Getting started with Editor extensions" site on the MSDN http://msdn.microsoft.com/en-us/library/dd885122.aspx
Thorsten
I'm wondering how others deal with trying to centralize MessageBox function calling. Instead of having long text embedded all over the place in code, in the past (non .net language), I would put system and application base "messagebox" type of messages into a database file which would be "burned" into the executable, much like a resource file in .Net. When a prompting condition would arise, I would just do call something like
MBAnswer = MyApplication.CallMsgBox( IDUserCantDoThat )
then check the MBAnswer upon return, such as a yes/no/cancel or whatever.
In the database table, I would have things like what the messagebox title would be, the buttons that would be shown, the actual message, a special flag that automatically tacked on a subsequent standard comment like "Please contact help desk if this happens.". The function would call the messagebox with all applicable settings and just return back the answer. The big benefits of this was, one location to have all the "context" of messages, and via constants, easier to read what message was going to be presented to the user.
Does anyone have a similar system in .Net to do a similar approach, or is this just a bad idea in the .Net environment.
We used to handle centralized messages with Modules (VB). We had one module with all messages and we call that in our code. This was done so that we change the message in one place (due to business needs) and it gets reflected everywhere. And it was also easy to handle change in one file instead of multiple files to change the message. Also we opened up that file to Business Analysts (VSS) so that they can change it. I don't think it is a bad idea if it involves modules or static class but it might be a overkill to fetch it from DB.
HTH
You could use resource files to export all text into there (kinda localization feature as well). Resharper 5.0 really helps in that highlighting text that can be moved to resource.
Usually it looks like this:
Before: MessageBox.Show(error.ToString(), "Error with extraction");
Suggestion: Localizable string "Error with extraction"
Right click Move to Resource
Choose resource file and name (MainForm_ExtractArchive_Error_with_extraction), also check checkbox Find identical items in class ...
Call it like this MessageBox.Show(error.ToString(), Resources.MainForm_ExtractArchive_Error_with_extraction);
Best of all it makes it easy to translate stuff to other languages as well as keeping text for MessageBox in separate Resource. Of course Resharper does it all for you so no need to type that much :-)
I suppose you could use a HashTable to do something similar like this, this can be found in:
using System.Collections;
To keep it globally accessable i was thinking a couple of functions in a class holding the hashtable to get/set a certain one.
lets see now.
public class MessageBoxStore
{
private HashTable stock;
public string Get(string msg)
{
if (stock.ContainsKey(msg))
return stock[msg];
else
return string.Empty;
}
public string Set(string msg, string msgcontent)
{
stock[msg] = msgcontent;
}
}
or something like that, you could keep multiple different information in the hashtable and subsequently compose the messagebox in the function too.. instead of just returning the string for the messagebox contents...
but to use this it would be quite simple.
call a function like this on program load.
public LoadErrorMessages()
{
storeClass = new MessageBoxStore();
storeClass.Set("UserCantDoThat", "Invalid action. Please confirm your action and try again");
}
for example, and then.
MessageBox.Show(storeClass.Get("UserCantDoThat"));
i put this in a new class instead of using the HashTable get/set methods direct because this leaves room for customization so the messagebox could be created in the get, and more than 1 piece of information could be stored in the set to handle messagebox title, buttontype, content, etc etc.
Basically I'm trying to implement some sort of poor man's Aspect Oriented Programming in C#. I had thought about using a ContextAttribute but they seem only be be bound at the class level. Is there any way that I can put an attribute in such that it will receive the same parameters as the method which it annotates or some way to access the context in which it fired?
I have this code
public void AddUser(User user)
{
var errors = DataAnnotationsValidationRunner.GetErrors(user);
if (errors.Any())
throw new RulesException(errors);
users.Add(user);
}
from which I would like to extract the first 3 lines so I had something like
[Validated]
public void AddUser(User user)
{
users.Add(user);
}
I think you are missing a third component. Most AOP implementations (e.g. Aspect#) rely on a proxy or interceptor to actually execute the code. In your scenario, you lack whichever component needed to 1) know the attribute exists on the method, and 2) trigger the mechanism (or become it) needed to execute the code within the attribute.
Fortunately, there are already many (fairly) simple solutions available in open source. The simplest option I can think of would be to use a compile-time weaver like PostSharp. Grab a copy of that, and in the samples you'll find several examples of exactly what you are trying to do (you'd be interested in the OnMethodInvocationAspect).
The end result is that your code looks exactly like it does in the sample you provided, yet it's also running the code you wish.
Don't know exactly how your solution should look like, but in C# attributes do not execute code as long as you don't request them (as far as I know). And if you query for the attribute, you also have the context. So there is something wrong with your strategy in my opinion.