Situation :
To run integration tests on our ASP.NET MVC application, we chose Selenium's Web Driver.
Problem :
When running the tests from VS2015 using Internet Explorer Driver, the console displays an error message (see screenshot below).
Simultaneously, the browser opens and closes. The console freezes. Then, Visual Studio displays a StackOverflow exception message :
Diagnostic :
The test crashes as soon as the driver attempts a navigate action in the app.
[Test]
public void PerformNavigation()
{
Driver.Navigate().GoToUrl(GetAbsoluteUrl("/")); // <-- The test crashes here
}
However an external url works.
[Test]
public void PerformNavigation()
{
Driver.Navigate().GoToUrl("http://google.com"); // <-- This works
}
It seems that the web driver is redirected forever until a stackoverflow exception occurs (HTTP 302).
In debug mode, I can not find the main project's assembly (the one we are testing) in the modules window. It seems that the test project has some trouble loading this specific assembly : all other assemblies are here. I did not find any reason why an assembly couldn't be loaded.
Question :
I could not find any help on Google or SO. Our problem is very specific and may be a combination of issues.
So how can I make these integration tests work ?
Or at least : how can I perform a more precise diagnostic on this issue ?
UPDATE :
I eventually found out that the annotations before my controller methods were interfering with my tests. We use these annotations to check the user rights (here the user can read or update missions) :
[AuthorizedFunctionalities(Functionalities = "Mission_R;Mission_CUD")]
However I find it strange that these tests can not work with such annotations. They work well in debug mode but not through web drivers.
I'll try to investigate further.
You could try to load the assembly (.dll) dynamically, staight in the C# code, at the beginning of the tests.
To do so, you can use the following line of code :
Assembly.LoadFile($"{AppDomain.CurrentDomain.BaseDirectory}\\YourDLL.dll");
I eventually found out that the annotations before my controller methods were interfering with my tests. We use these annotations to check the user rights before the controller's methods:
[AuthorizedFunctionalities(Functionalities = "MyFunctionalities")]
By removing these anotations, the tests work. I still need to know why the web driver doesn't like these.
Related
I am trying for the very first time to use Selenium. I would like to have a console application that opens a browser, goes to a website, and performs some actions.
To do this I looked up some tutorials. The first one I found is here:
https://learn.microsoft.com/en-us/microsoft-edge/webdriver-chromium/?tabs=c-sharp
I would like to automate Edge.
The first thing I did was get my Edge version, which incidentally decided to update when I went to the about page, something that will no doubt be a problem going forward.
I downloaded the file that corresponded to my version, although for some reason that version is x86 only while all the others are x64...
I then went to NuGet and searched for Selenium.WebDriver. Probably because I'm targeting 4.7.2 the latest version is 3.141 not version 4, but whatever. I install version 3.
I also add a nuget reference to Microsoft.Edge.SeleniumTools as instructed in the guide.
the guide then says use this code:
var options = new EdgeOptions();
options.UseChromium = true;
var driver = new EdgeDriver(options);
However I don't have a UseChromium property, so this does not work.
I removed it, and used the default constructor, however this also doesn't work because it can't find the driver.
So next I passed in the path to the folder the driver is in as a parameter.
This also did not work because it is looking for a file with a different name to the one in the edge driver zip download. It looks for microsoftwebdriver.exe while the zip file contains msedgedriver.exe. Perhaps this is the reason for the error? It actually has a link in the exception when it can't find it of where to download it, however the link is dead.
I renamed the file, and ran the code. A console window appeared with debug information, and the browser opened. Success!
Next I tried to go to a website, with this code:
driver.Url = "https://www.google.com";
However with this I got these errors in the console window:
Starting MSEdgeDriver 94.0.992.38
(55a0a486d5c4c1a7374dc28a7be702fee43b3b39) on port 1307 Only local
connections are allowed. Please see
https://chromedriver.chromium.org/security-considerations for
suggestions on keeping MSEdgeDriver safe. MSEdgeDriver was started
successfully.
DevTools listening on
ws://127.0.0.1:1310/devtools/browser/c4e7f6f6-46d3-447c-b26b-3ad231a6122f
[29296:584:1001/203949.853:ERROR:fallback_task_provider.cc(119)] Every
renderer should have at least one task provided by a primary task
provider. If a fallback task is shown, it is a bug. Please file a new
bug and tag it as a dependency of crbug.com/739782.
[29296:26032:1001/203954.115:ERROR:chrome_browser_main_extra_parts_metrics.cc(250)]
crbug.com/1216328: Checking default browser status started. Please
report if there is no report that this ends.
[29296:584:1001/203954.143:ERROR:profile_manager.cc(1057)] Cannot
create profile at path
C:\Users\NibblyPig\AppData\Local\Microsoft\Edge\User Data\Default
[29296:584:1001/203954.143:ERROR:profile_manager.cc(2010)] Cannot
create profile at path
C:\Users\NibblyPig\AppData\Local\Microsoft\Edge\User Data\Default
[29296:26032:1001/203954.176:ERROR:chrome_browser_main_extra_parts_metrics.cc(254)]
crbug.com/1216328: Checking default browser status ended.
The code then crashes with OpenQA.Selenium.WebDriverException: 'unknown error: net::ERR_CONNECTION_TIMED_OUT
I've tried googling the fallback task provider error and also looking at the profile error, but there is very little information and I am at a loss of what to do.
I wonder if anyone could advise what steps I might take to get this working.
First, if you use WebDriver with Selenium 3, the Selenium Tools for Microsoft Edge package must be installed.
Did you import the wrong package? Make sure it is using Microsoft.Edge.SeleniumTools; not using OpenQA.Selenium.Edge;.
This is my simple test, and it works well:
public static void Main() {
var options = new EdgeOptions();
options.UseChromium = true;
options.BinaryLocation = #"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";
var driverPath = #"C:\Users\Administrator\Desktop";
var driver = new EdgeDriver(driverPath, options);
driver.Url = "https://www.google.com/";
}
Note: Please modify the path parameters according to your own situation.
I've created the WCF service and some simple WPF application consuming it. When I'm running the project from within Visual Studio, the WCF Test Client opens and the application works just fine, method defined in service work.
But I need to host this WCF service in a Windows Service. I've followed this, installed the services using Installutil.exe and the ran the service. Everything went fine, it's working.
Yet, when I'm trying to open the executable file with WPF application directly from the debug folder of the app, I'm getting this error:
zad8. has stopped working
After choosing the option to debug it with new instance of VS I get
XamlParseException occured in PresentationFramework.dll
The stack trace shows something like:
connection can't be started, because the target computer is actively refusing it
Do you have any idea what could go wrong?
Fortunately, I've managed to come up with solution. I think I should post it, maybe one day it will help somebody:)
I actually did two mistakes, but one of them was unfortunately caused by the mentioned tutorial (here) in connection with my temporary blackout.
In step 5, point 8 of this tutorial, there's an example of overriding OnStart() method:
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(Service1));
myServiceHost.Open();
}
Beware, that Service1 is ambiguous in this context, because it's name of the Windows Service project class as well as the name of WCF Service class. It should be written with fully qualified name (here it is WcfServiceLibrary1.Service1). In my case, the service name was different, and I just put the Service1 in there in a hurry. Anyway..
In case, someone has it all behind and still encounters the same problem (with app stopped working), I think that you should try open the project in Visual Studio and try to debug the client consuming application as a new instance (right click on the project-> Debug -> Start as new instance...).
It might seem trivial, but when u hit F5 or Ctrl+F5 then even if u have only those project set as startup project, VS will host it's client anyway. In my case it did matter, because I needed to use isolation storage file. And as it was kept on the service side, then I had this file created in IIS server created by VS. Somehow, my method of creating such file had set FileMode.Open() and it was causing the crush, because in Windows Service it didn't exist and the new one couldn't be created and that was neccessary to run it correctly.
What's more it just showed me that this question couldn't be answered properly, cause the data I've provided was not enough and it was delicate.
Cheers:)
I have written some code in the application_start() method in my global.asax file. It does not get called when I deploy my application on IIS server. The code is accessible when I run it in the .NET framework.
I've tried to restart the application many times, but it's still not working.
I've also tried the suggestion from the following link.
Application_Start not firing?
There are few things you need to know before you are trying to debug Appplication_Start. There are -
One : When the code executes and why it is almost impossible to debug by attaching to it.
The application start method is executed when the application pool starts and your website is being started up for the first time. If you deploy new deliverables to IIS, then IIS might restart it itself, but there is no guarantee that it will. So, deploying new codes does not guarantee that it will restart the pool and he execution of application start. You should restart your application pool to guarantee execution of application start.
While debugging IIS applications, Visual Studio attaches itself to a process something named w3wp.exe or similart (I forgot the actual executable name), which is the worker process and only available after, remember after, your application pool is up and your site is up. So, in other words, if you are seeing this in service list, then the application start has already been executed and attaching to it will not give you a chance to debug it. It is kind of a tug of war with time.
So, in other words, it is kind of impossible to debug application start unless you are very very quick.
Two, the solution 1 - With Dev Server
Launch your application in visual studio with Asp.net development server or IIS express, then you will be able to debug. But if you really want to debug on IIS, then check the next section
Two, the solution 2 - With IIS
There is a library in the name System.Diagnostics, Debuggerand it has a nice way to call debugger in code. You can read it here - http://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.break(v=vs.110).aspx
Modify you application start with this -
public void Application_Start(){
....... //other codes
Debugger.Break() or Debugger.Launch()
}
When this line executes, IIS will halt execution, and will show you a debugger selector window (similar to the one attached), keep your solution open in vs and select that vs from the list, will be able to debug as usual... :)
In case you are using windows 8 and the debugger does not launch, read this article to enable it -
http://blogs.msdn.com/b/mapo/archive/2013/11/07/debugger-launch-not-displaying-jit-debugger-selection-popup-on-windows-8-8-1.aspx
Three: A very important thing
I noticed that you said, you are adding db entries in Application_Start. You should keep in mind that, Application_Start does not have a HttpContext, ViewContext, So your db access code may fail for so many others reasons.
Make sure that the Global.asax file is actually deployed to the destination folder in the root. If the file is not present then the code behind you have written for Application_Start will never be called.
Also make sure the signature is correct
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {/*do something here like logging so you know it was called*/}
}
If you are running Server 2008R2 (or earlier) and/or IIS 7.5, you might want to look into the Application Initialization module. This can be downloaded here:
www.iis.net/downloads/microsoft/application-initialization
With IIS versions prior to 8.0, the application start is not called until the first web request arrives. I'm reading your question as you want your application start to be fired before the first web request, yes?
Here is a fantastic guide to configuring this module (if it applies to you):
https://blogs.msdn.microsoft.com/benjaminperkins/2014/01/07/configure-the-iis-application-initialization-module/
The key takeaways is that you need to set your app pool to 'AlwaysRunning' instead of 'OnDemand'. You also need to set a preloadEnabled flag for your website. Once both of these are done, fire off an iisreset and you should see the results of your application start (look in the database since it's writing there).
Other answers are relevant as well, in that this is tough to debug and you're missing all the niceties you're used to such as a httpcontext in app start.
If you are running IIS 8.0 - you should still read the above link to configure preloading.
This did work for me:
Menu -> Build -> Clean Solution
Menu -> Build -> Rebuild Solution
Then, Application_Start() was fired only for the first time.
In my case in production environment App_global.asax.compiled was missing and all content of global.asax not fired.
I need to change my unit test from local to remote tests and so far I thought that all I had to do is change UrlToTest to point to another server... But VS keeps on insisting to create a Development Web Server instead of using the one that is already running.
So after reading some docs my question actually is do I have install Test Controller and Test Agent on both remote and local computer or what? What if the WebService is on Linux...
Note that I don't want to debug the application that I'm testing. I simply want tests to be executed for a WebService that is already running, that is deployed.
I probably should mention that all my tests consists of WebService calls and some checks like this:
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("MainProjectName", "/")]
[UrlToTest("http://servername:port/websitename/TestingOnlyWebForm.aspx")]
public void LoginEmptyDataTest()
{
IUserService userService = CreateIUserService();
string email = "";
string password = "";
ReturnMessage<User> actual;
actual = userService.Login(email, password);
Assert.AreNotEqual(true, actual.Status);
Assert.AreNotEqual("db_error", actual.Info);
}
But I have also more complicated tests in which I change some data and send it to another WebService and so on.
Note that UrlToTest previously was pointing to localhost at which point it works but starts a developer server which is not what I want.
What you are trying to is not possible. All that generated unit test is trying to do is to run the test locally on the machine either using the development server by specifying AspNetDevelopmentServerHost or by using local IIS, when AspNetDevelopmentServerHost is not present.
If you want to test remote services right click your unit test project and add a service reference. Point to your service give it a namespace, say Services, and generate the proxies. Once you have the proxies generated just instantiate them and call the methods. Also remove all the unneeded attributes from your test. Your test should roughly look like this:
[TestMethod]
public void LoginEmptyDataTest()
{
using (var userServiceClient = new Services.UserServiceClient(
"BasicHttpBinding_IUserService",
"http://someremotehost/userservice.svc"))
{
var result = userServiceClient.Login("user", "password");
// asserts go here
}
}
This may solve your immediate problem however you should re-think what you are doing as #eglasius said. what happens if the code you call changes state internally? Next test might fail because of that so you need clean-up strategies otherwise your tests will be very brittle and you'll end up ignoring them.
Update: passing an address at run-time. Change the first parameter to whatever enpoint configuration name you have in your config file.
I'll take a stab in the dark at this one because I did something similar recently.
In my case my test project referenced the service project to provide visibility of the service and data contracts the Web Service implements and consumes.
To resolve this - though it can be ignored - move the contracts to a new project. Then have the service and test projects reference the new project, and remove the test projects' reference to the service.
Hope that makes sense!
Once the reference is removed, VS will no longer feel the need to start up your service when you run your tests.
You can disable the startup of the Service Host in the Project settings of your WCF Service Project. Right Click - WCF Options - Uncheck "Start WCF Service Host when debugging another project in the same solution".
You really have to consider the nature of what you're trying to achieve here.
It's hard to tell exactly what you're hitting of the code. I have the impression, you have is a website that calls a web service. You're testing the client code in that context, instead of just testing the service.
If that's the case, remove the attributes and point the url to the correct service like UrbaEsc guided you to. If you don't remove the attributes, you're running the calling code in the context of the site.
Even if the above is not the scenario, and based on what you replied to UrbanEsc in the comments, you'd then be testing an external call to the webservice initiated from the same site process.
You said:
"Found it, but VS still starts something on localhost and then trys to reach external server... Seems like VS is just not designed for real remote testing of webservices"
Read the above. I'd say you need to better understand what you're enabling. You can certainly test remote web services, like you can do pretty much anything you can code. You do that from client code that knows nothing different that what any other external client of the service would know. Support doesn't stop there, as you can do load testing of the service.
Note that what you're doing aren't unit tests, these are integration tests. Or depending on the scope of your system, full system tests.
I have a project that is deployed to production as a windows service. However for local development purposes it would be useful to run it as a console application. At the moment I have a class Called ReportingHost that provides my core functionality, And a class called ReportingServiceHost that inherits from ServiceBase and allows me to run the application as a service. There is also a program class with a main method that calls ServiceBase.Run on my ReportingServiceHost.
I think I need to write a ReportingConsoleHost class that allows me to run the functionality in a console. Then I need to modify my Main to react to a command line switch and choose one or the other. These are the two bits I am having trouble with.
I have had a look at this and attempted to use that code but my app exits immediately, it doesn't show a console window and it doesn't wait for Enter before closing.
Part of the problem is that I dont have a deep understanding of how these things work. a definitive pattern for splitting my functionality, my two different ways of running that functionality, and a main method that chooses one of these ways based on a command line argument is what I am hoping to achieve.
I suspect your test project was configured as a windows exe, not a console exe. With a windows exe Console.ReadLine will return immediately.
To have a console exe that works both as a service and at the command line, start it as a service project (in Visual Studio) - and add a check on Environment.UserInteractive - i.e.
static void Main() {
if(Environment.UserInteractive) {
// code that starts the listener and waits on ReadLine
} else {
// run the service code that the VS template injected
}
}
You can of course also use a command line switch. I have example on microsoft.public.dotnet.languages.csharp that acts as:
an installer / uninstaller
a service
a console-mode app
depending on the switches
I have done this before by implementing a normal Windows Service (by deriving from ServiceBase), but putting a check in the main method to check for a command line argument.
If the args contain /console, start the console version, otherwise start the service.
Something like this:
internal class MyService : ServiceBase
{
internal static void Main(string[] args)
{
if (args.Length == 0)
{
// run as a service....
ServiceBase[] servicesToRun = new ServiceBase[] {new MyService()};
Run(servicesToRun);
}
else
{
// run as a console application....
}
}
}
My advise? Put all your logic for your service in a separate assembly. (A class library or DLL.) Then create one project as service which references your class library and puts the code to use as services. Create a second console project which also references your class library but which will make it available as a console application.
You would end up with three different projects in your solution but it does allow you to keep things separate. Actually, this would make it possible to extend your service in several other shapes too. You could, for example, create a 4th project as a web service and thus call your service from a web browser on a client system. Because the software logic is separated from the usage logic, you gain lots of control over it.
Be aware that a service will possibly run with more limitations than a console application. In general, services don't have network access by default, don't have a monitor assigned to them to display error messages and in general run with a limited user account or system account. Your service might work as a console yet fail as a service because of this.
There are already two good answers above - but I thought I'd post a link to Brian Noyes' Debuggable Self-Host Windows Service Project blog post - it talks about WCF but should apply to any 'Windows Service'.
The best thing is the sample code - if you can't figure out where the above examples 'fit', grab the complete project and see how it works. Thanks Brian!