I'm trying to execute NUnit tests through a Windows Form application with NUnit Engine, but I don't understand how to set the path for the DLL where my tests are (I have already included the DLL in the references). When I click a button, I want the tests to start; however, NUnit opens and then immediately closes without doing anything. Here's what I have:
namespace ATF.GUI
{
public partial class ATF_Main : Form
{
TestPackage package;
ITestEngine engine;
public ATF_Main()
{
InitializeComponent();
}
private void ATF_Main_Load(object sender, EventArgs e)
{
string path = Assembly.GetExecutingAssembly().Location;
package = new TestPackage(path);
package.AddSetting("Working Directory", Environment.CurrentDirectory);
// Prepare the engine
engine = TestEngineActivator.CreateInstance();
}
private void btnStartTests_Click(object sender, EventArgs e)
{
using (ITestRunner runner = engine.GetRunner(package))
{
// Execute the tests
XmlNode result = runner.Run(null, TestFilter.Empty);
}
}
I never got a real answer to this but I figured it out myself.
private void ATF_Main_Load(object sender, EventArgs e)
{
// Add reference to tests DLL and load it here by name
Assembly testAssembly = Assembly.Load("Program.Tests");
package = new TestPackage(testAssembly.Location);
package.AddSetting("Working Directory", Environment.CurrentDirectory);
}
You could also add the assembly locations to a List if you have multiple test assemblies.
You are setting the test assembly to be your gui assembly. Since it has no tests, NUnit finds nothing to do. I imagine it returns an error in the result.
Somehow, your application has to be given the path of the test assembly. This can be through a command-line or a dialog of some kind. You can look at the code for nunit3-console or nunit-gui to see how it is done.
Your idea of using a referenced assembly seems a bit odd for a packaged application. Your users will need to have the source and rebuild it each time, referencing the desired test assembly. Do you really want that?
In case you do, you will need to find some way to get at that reference. Hard to do if there is nothing constant that will always be in it.
Related
I'm using Pomelo.EntityFrameworkCore.MySql (3.1.1) to save some data to MySql. When the context is first configured I'm getting this exception:
Exception thrown: 'System.MissingFieldException' in Pomelo.EntityFrameworkCore.MySql.dll
Field not found: 'Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning'
Here's my OnConfiguring:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// This works just fine, even though that type is then not available in `UseMySql`.
var test = Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning;
// Exception thrown here.
optionsBuilder.UseMySql("server=localhost;database=test;uid=user;pwd=<password>;TreatTinyAsBoolean=true;", x => x.ServerVersion(new Version(5, 7, 29), ServerType.MySql));
}
}
Possible complicating factor: The app is an addin for Autodesk Revit. I've had some dll loading issues which I believe I've worked out, but it is a non-standard environment which could be causing issues. I've verified that Microsoft.EntityFrameworkCore.Relational, the dll that provides AmbientTransactionWarning, is loaded when UseMySql is called. Also, while VS is paused on the exception, if I enter Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning in the Immediate window, I don't get an error. I also have another stand-alone WPF app that uses the same database model and DbContext object, which communicates with the database just fine.
I'm not sure how to proceed in debugging this. Thanks!
Edit
Both the addin and Revit (2020) are using .NET Framework 4.7.2.
Stacktrace:
Field not found: 'Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning'.
at Microsoft.EntityFrameworkCore.MySqlDbContextOptionsExtensions.ConfigureWarnings(DbContextOptionsBuilder optionsBuilder)
at Microsoft.EntityFrameworkCore.MySqlDbContextOptionsExtensions.UseMySql(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 mySqlOptionsAction)
at <MyAssembly>.DatabaseContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder)
Library Loading
Typically Revit addins load their dependencies automatically as needed. Occasionally not, though, so I have added the following resolver which manually loads assemblies which in past runs have failed to load automatically:
// Executed on first run of addin.
AppDomain.CurrentDomain.AssemblyResolve += ResolveMissingAssemblies;
...
private System.Reflection.Assembly ResolveMissingAssemblies(object sender, ResolveEventArgs args)
{
string[] dlls = new[]
{
"System.Memory",
"System.Buffers",
"System.Threading.Tasks.Extensions",
"System.Runtime.CompilerServices.Unsafe",
"Microsoft.EntityFrameworkCore.Relational",
"Microsoft.EntityFrameworkCore",
"MySqlConnector",
};
string dll = dlls.FirstOrDefault(name => args.Name.Contains(name));
if (!string.IsNullOrEmpty(dll))
{
string filename = Path.Combine(
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
$"{dll}.dll");
if (File.Exists(filename))
{
return System.Reflection.Assembly.LoadFrom(filename);
}
}
return null;
}
The more I look at this the more it seems that somehow the field in question is available in my main assembly but not in EntityFrameworkCore. I'm not sure why or how that would be the case. I've also tried using IlMerge to combine various parts of the addin, but haven't been able to get anything working in that direction.
This is likely an issue in resolving dependent assemblies.
You probably want to debug your ResolveMissingAssemblies() method (or log all assemblies that your event handler is unable to resolve).
Also output/take a look at the ResolveEventArgs.RequestingAssembly property, that tells you what assembly the current one is a dependency of (to understand the dependency tree).
The Microsoft.EntityFrameworkCore.Relational assembly e.g. depends on Microsoft.EntityFrameworkCore, which depends on 10 other libraries (some of which depend on other libraries again).
A simple way to ensure they are all being loaded, is to make your event handler a bit more generic:
private System.Reflection.Assembly ResolveMissingAssemblies(object sender, ResolveEventArgs args)
{
string filename = Path.Combine(
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
$"{args.Name}.dll");
return File.Exists(filename))
? System.Reflection.Assembly.LoadFrom(filename)
: null;
}
I am trying to make some coded UI tests to help automate some of the manual testing at the company I work at. I am pretty new to the CUIT part of visual studio, but I feel like I am figuring it out. However I am having an issue with the testing thread being closed before the other tests run.
So I want to make this testing fully automated, as in, all the developer will need to do is to click "Run all" and they will all run automatically. The problem that I am having is that the very first test needs to launch Internet Explorer, go to a website, and log into the website. The rest of the tests are based off of being logged into the system. However, after the first test, the browser closes and gets killed along with the first test method.
Any advice on this would be great, I have searched online for some answers but a lot are for very old versions of visual studio, and the ones I have tried don't work.
Thank you.
Edit: So inside each class lets say "CodedUITest1.cs", I can use the same browser in each of the [Test Method]s that I have in that class (as someone suggested below). The issue I have is that if I want a different test class to test different functionality, "CodedUITest2.cs", the browser will close when the first class finishes its tests.
If I'm understanding your question correctly, then This code segment should work for you:
BrowserWindow window;
[TestMethod]
public void Method1()
{
window = BrowserWindow.Launch(new Uri("http://www.bing.com"));
window.CloseOnPlaybackCleanup = false;
}
[TestMethod]
public void Method2()
{
window = BrowserWindow.Locate("Bing");
window.CloseOnPlaybackCleanup = false;
}
[TestMethod]
public void Method3()
{
window = BrowserWindow.Locate("Bing");
}
After reading the new info of this question, I have tested the code a bit. If you want to keep the browser open between CodeUITes1.cs and CodedUITest2.cs, then the following code segment may help you. It is adopted from the following link: https://blogs.msdn.microsoft.com/devops/2012/11/08/coded-ui-test-why-does-application-close-after-each-test-in-visual-studio-2012/
File: CodedUITest1.cs
public class CodedUITest1
{
static BrowserWindow browserWindowInstance = null;
public void LoadLocalHost()
{
if (browserWindowInstance == null)
{
browserWindowInstance = BrowserWindow.Launch(new System.Uri("YourWebSiteAddress"));
browserWindowInstance.CloseOnPlaybackCleanup = false;
browserWindowInstance.Maximized = !browserWindowInstance.Maximized;
}
else
{
browserWindowInstance.Maximized = !browserWindowInstance.Maximized;
}
}
[TestMethod]
public void CodedUITestMethod1()
{
LoadLocalHost();
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
this.UIMap.ClickNewsAndEvents();
}
CodedUITest2.cs file:
[TestMethod]
public void CodedUITestMethod2()
{
CodedUITest1 obj1 = new CodedUITest1();
obj1.LoadLocalHost();
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
this.UIMap.ClickNewsPage();
}
You can add more CodedUITest classes. Just create a new object like obj1 in the code sample of CodedUITest2 class, and use LoadLocalHost() method that resides in CodedUITest1.class from any subsequent classes. Hoping this will resolve your problem.
I have a VS solution set up using build scripts to copy the compiled DLL into another project. The base project builds fine, and copies correctly to the target.
However, the target project won't compile as it can not find a particular class within the namespace:
foo.cs
namespace foo {
public class bar {
public static string myVar {
get { return "A string"; }
}
}
}
myPage.aspx.cs
using foo;
namespace foo.foo2 {
partial class bar2 {
protected void Page_Load(object sender, EventArgs e) {
// can access foo.bar here in the source project but not once the DLL is compiled and copied to target
var myVar = bar.myVar; // The name 'bar' does not exist in the current context
}
}
}
Why would this compile correctly in the source project, but prevent the target from building?
EDIT: Second project builds fine if I exclude myPage.aspx from the project. But I shouldn't have to do that.
You have very likely an incorrect assembly referenced.
Make sure you use the correct physical assembly. Sometimes, a dead (old) version lies around (such as in the GAC) and this one is referenced rather than the believed new version.
Easiest way to confirm is to rename the assembly file to something else and reference the newly named assembly. bar.myVar should show up immediately.
I'm working on a plugin for a existing C# .NET Program. It's structured in a manner where you put your custom .dll file in Program Root/Plugins/your plugin name/your plugin name.dll
This is all working well, but now I'm trying to use NAudio in my project.
I've downloaded NAudio via Nuget, and that part works fine, but the problem is that it looks for the NAudio.dll in Program Root, and not in the folder of my plugin.
This makes it hard to distribute my plugin, because it would rely on users dropping the NAudio.dll in their Program Root in addition to putting the plugin into the "Plugins" folder.
Source:
SettingsView.xaml:
<Button HorizontalAlignment="Center"
Margin="0 5"
Width="120"
Command="{Binding SoundTestCommand,
Source={StaticResource SettingsViewModel}}"
Content="Sound Test" />
SettingsViewModel.cs:
using NAudio.Wave;
.
.
.
public void SoundTest()
{
IWavePlayer waveOutDevice;
WaveStream mainOutputStream;
WaveChannel32 inputStream;
waveOutDevice = new WaveOut();
mainOutputStream = new Mp3FileReader(#"E:\1.mp3");
inputStream = new WaveChannel32(mainOutputStream);
inputStream.Volume = 0.2F;
waveOutDevice.Init(mainOutputStream);
waveOutDevice.Play();
}
How can I get C# to look for NAudio in Program Root/Plugins/my plugin name/NAudio.dll instead of looking for it in Program Root/NAudio.dll ?
I'm using VS Express 2013, Target Framework is 4.5 and Output type is Class Library.
Edit:
I found 2 ways to make this work ( I'm not sure what the pros and cons of both methods are - if anyone knows I would appreciate additional information ).
Using the NuGet Package Costura.Fody.
After installing the NuGet package, I simply had to set all other References "Copy Local" to "False" and then set "Copy Local" for NAudio to "True".
Now when I build, the NAudio.dll is compressed and added to my own DLL.
Using the AssemblyResolver outlined below.
It didn't work right away though, so here is some additional information that may help anyone facing the same issue:
I put Corey's code as he posted it into the Helpers folder.
My entry point is Plugin.cs, the class is public class Plugin : IPlugin, INotifyPropertyChanged
In there, the entry method is public void Initialize(IPluginHost pluginHost), but simply putting PluginResolver.Init(path) did not work.
The host program uses WPF and is threaded and I had to use a dispatcher helper function of the host program to get it to work: DispatcherHelper.Invoke(() => Resolver.Init(path));
As mentioned, I'm currently unsure which method to use, but I'm glad I got it to work. Thanks Corey!
You can use the PATH environment variable to add additional folders to the search path. This works for native DLLs, but I haven't tried to use it for .NET assemblies.
Another option is to add a hook to the AssemblyResolve event on the current application domain and use a custom resolver to load the appropriate assembly from wherever you find it. This can be done at the assembly level - I use it in NAudio.Lame to load an assembly from a resource.
Something along these lines:
public static class PluginResolver
{
private static bool hooked = false;
public static string PluginBasePath { get; private set; }
public static void Init(string BasePath)
{
PluginBasePath = BasePath;
if (!hooked)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolvePluginAssembly;
hooked = true;
}
}
static Assembly ResolvePluginAssembly(object sender, ResolveEventArgs args)
{
var asmName = new AssemblyName(args.Name).Name + ".dll";
var assemblyFiles = Directory.EnumerateFiles(PluginBasePath, "*.dll", SearchOption.AllDirectories);
var asmFile = assemblyFiles.FirstOrDefault(fn => string.Compare(Path.GetFileName(fn), asmName, true) == 0);
if (string.IsNullOrEmpty(asmFile))
return null;
return Assembly.LoadFile(asmFile);
}
}
(Usings for the above: System.IO, System.Reflection, System.Linq)
Call Init with the base path to your plugins folder. When you try to reference an assembly that isn't loaded yet it will search for the first file that matches the base name of the assembly with dll appended. For instance, the NAudio assembly will match the first file named NAudio.dll. It will then load and return the assembly.
No checking is done in the above code on the version, etc. and no preference is given to the current plugin's folder.
I'm making a program depending on some DLLs included in a third party program. I'm not allowed to distribute these DLLs myself. The third party program must be installed for my program to work.
How can i make a reference to these DLLs? I know the exact location of them through a registry key set by the program.
I have tried to add the files in Project->References and set CopyLocal to false but when i start i then get a FileNotFoundException "Could not load file or assembly".
I have tried to add an event to AppDomain.CurrentDomain.AssemblyResolve and load the files there but the problem is that i get the exception before my program even starts. Even if i put a breakpoint on the first line the exception will be thrown before the breakpoint is hit.
From C# 3.0 in a Nutshell, 3rd edition, by Joseph and Ben Albahari, p. 557-558:
Deploying Assemblies Outside the Base Folder
Sometimes you might choose to deploy assemblies to locations other than the application base directory [...] To make this work, you must assist the CLR in finding the assemblies outside the base folder. The easiest solution is to handle the AssemblyResolve event.
(We can ignore the fact that in your case, someone other than you is deploying the assemblies.)
Which you tried. But a very important clue follows somewhat later. Read the two code comments:
public static void Loader
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += FindAssem;
// We must switch to another class before attempting to use
// any of the types in C:\ExtraAssemblies:
Program.Go();
}
static Assembly FindAssem(object sender, ResolveEventArgs args)
{
string simpleName = new AssemblyName(args.Name).Name;
string path = #"C:\ExtraAssemblies\" + simpleName + ".dll";
if (!File.Exists(path)) return null;
return Assembly.LoadFrom(path);
}
}
public class Program
{
public static void Go()
{
// Now we can reference types defined in C:\ExtraAssemblies
}
}
As you see, the class where you resolve the external assemblies must not refer to any type from any of the external DLLs anywhere. If it did, code execution would stop way before your AssemblyResolve ever gets a chance to run.
Your app bombs because the JIT compiler is the first one that needs to load the assembly. You'll need to carefully avoid using types from the assembly in your Main() method. That's not hard to do, just write another Main method and give it an attribute that tells the jitter that it should never inline that method. Without the attribute it may still bomb in the Release build when the optimizer inlines the method. Like this:
using System;
using System.Runtime.CompilerServices;
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
DelayedMain(args);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void DelayedMain(string[] args) {
// etc..
}
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
// etc...
}
}
Before you commit doing it this way, do contact the vendor and ask for recommendations. There has to be an easier way to exercise your license rights. The GAC would be a common choice, maybe you just need to run gacutil on your dev machine.