I have a straightforward unit test class like so:
[TestClass]
public class SomeTests
{
[TestMethod]
public void Test1()
{
// make some assertions
}
[TestMethod]
public void Test2()
{
// make some assertions
}
// ...
[TestMethod]
public void Test50()
{
// make some assertions
}
}
and I basically want to run Test1..Test50 twice via the "Run All" command. Once with App.config like so:
<appSettings>
<add key="SomeSetting" value="true"/>
</appSettings>
and once with App.config like so:
<appSettings>
<add key="SomeSetting" value="false"/>
</appSettings>
Being lazy, I don't want to refactor & parameterize 50 tests. And obviously I don't want 50 duplicate tests.
I'm having a bit of a brain fart over this, apologies if it's blindingly obvious.
make SomeTests abstract.
Add two new projects, with the two different .config files.
In each project add a TestClass that inherits from SomeTests.
Run all will now run both sets of tests.
Create two Test Settings. Click Enable Deployment under the Deployment section. Add your two different App.Config files (one to each Test Settings). Execute your tests, then swap to the other TestSettings and execute them again.
Might be a way to run with all testsettings, but I haven't found it.
Related
When I'm trying to do unit tests on my solution (my solution contains 5 layers, DAO, Utilities, ENTITIES, UI, DB), in Utilites there is a class who creates a conection between DATABASE and the solution, it name is "CONEXION.cs"
When I do this:
[TestClass]
public class CONSULTARPERFILES
{
[TestMethod]
public void CONSULTARPERFIL()
{
var a = new PERFILESNEGOCIO();
var b = a.CONSULTARLISTADOPERFILES();
Assert.IsTrue(true,"No encontrado");
}
}
I get a null reference here var b = a.CONSULTARLISTADOPERFILES(); Debugging project, I found this:
public class CONEXION
{
public string CadenaConexion()
{
return WebConfigurationManager.ConnectionStrings["CadenaConexion"].ConnectionString;
}
}
My problem is this: return WebConfigurationManager.ConnectionStrings["CadenaConexion"].ConnectionString;
And I used this too: return ConfigurationManager.ConnectionStrings["CadenaConexion"].ToString();
This is my ConnectionString that is in my Web.config:
<connectionStrings>
<add name="CadenaConexion" connectionString="Data Source=LAPTOP-0KMO6KG3;Initial Catalog=Serviteca;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
how can I solved it? please
In order to use connection strings in unit tests, you'll need to create a separate app.config file inside the unit test project and copy the connection strings into it. It won't automatically pull from your web project.
Example Solution:
MyWebProject
web.config (with connection string)
MyUnitTestProject
app.config (with connection string)
Code running in MyUnitTestProject will pull configurations (connection strings, app settings, etc) from the app.config local to that project, not from web.config
Side note: Making DB calls inside a unit test is usually not a good idea. We tend to avoid hitting an actual DB inside unit tests as that is usually an indicator that the test is too big. It also doesn't work well when setting up CI/CD pipelines as they may not have access to your local dev database.
I've searched around and no answers have worked for me. I have 2 ASP.NET projects, one of them being my project, the other being a project containing unit tests.
# Projects
Project.Core
...
secretConnectionStrings.config
Web.config
Project.Tests
In Project.Core, I have a method that requests both a connection string (from secretConnectionStrings.config and an app setting from the web.config file. Executing on it's own, the correct values are pulled from both of these config files. However, I want to test this within my unit test.
My test looks like this (within Project.Tests):
[TestClass]
public class TestUserController
{
[TestMethod]
public void Post_ShouldReturnNewUser()
{
var controller = new UserController();
var result = controller.Post() as User;
Assert.AreNotEqual(result, null);
}
}
The line it bombs out on is this
string cacheConnection = ConfigurationManager.ConnectionStrings["RedisCache"].ConnectionString;
System.NullReferenceException: Object reference not set to an instance of an object
I've tried adding web.config and secretConnectionStrings.config as a link in my Project.Tests solution. That hasn't worked, and I do not want to interface to my web.config (I want the values as they are saved in Project.Core). Is there a solution where I can pull values from Project.Core's web.config into my unit test?
The project containing the unit tests will need its own config file for the ConfigurationManager to pull in the connection strings. The best way to set this up and the keep only 1 copy of the config file is to add the same file into each project that needs it, but add it as a linked file:
Don't forget to set the file properties so that it deploys with the executable code:
And add it as a deployment item to your test fixture(s):
[TestClass]
[DeploymentItem(#"db.config")]
public class MyTestFixture { ... }
Now, if you want to have centralized connection strings in two differently-named config files (app.config & web.config), then you can place them in a third file db.config and import that file into each of the other config files:
db.config
<connectionStrings>
<add name="testDb" connectionString="data source=(localdb)\v11.0;..."
providerName="System.Data.SqlClient" />
</connectionStrings>
app.config / web.config
<connectionStrings configSource="db.config" />
Make sure to set Copy To Output Directory for the imported config files in addition to your app.config or web.config and add them as deployment items to the test fixture with the attribute.
So I've done some looking around. Most of the threads I find seem related to people wanting to run log4net in their actual tests. Meaning they want log entries in their test class. I don't want log entries from my actual tests. But I do want the expected log entries from the code I am testing. This is my first time using Log4net. If I run the code on it's own, the log entries work. If I run a test, no log entries though. Im guessing it's not initialized properly or perhaps I don't have log4net setup correctly in my UnitTest (in appconfig or assembly maybe??). This is an MVC 5 application. Here is a basic example.
Nunit Test (basics):
namespace MyUnitTests
[TestFixture]
public class MyTestClass
{
[Test]
public void MyTest
{
//arrange
var testVar = #"string";
//act
MyProjectClass.Method(testVar);
//assert something
}
}
so over in MyProject I have (basics):
public class MyProjectClass : Controller
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(MyProjectClass));
public static void Method(string myString)
{
//does whatever
log("added value");
}
So I've obviously simplified this for the discussion. But when I run my actual test, my test passes, the values and the outcome are all as they should be. I just never see the log entry in the log for method I just tested. Im sure I'm missing something simple. Any help would be greatly appreciated. Thanks!
If you look in the app.config for your main project, you should see a log4net config section that specifies the location of the log file.
You first need to add log4net to your <configSections> like this:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net, Version=1.2.10.0,
Culture=neutral, PublicKeyToken=1b44e1d426115821" />
</configSections>
You can then add a <log4net> section to the <configuration> tag. Documentation for this can be found here.
I just want to add the above answer. In addition to setting the appconfig in your UnitTest the same as your Application webconfig (editing the value for log file location if you want) you also need to add the assembly entry as you would have for your application already (changing web.config to app.config in my case).
//logger
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "app.config", Watch = true)]
You'll also need to initialize the logger (at least I did) in your unit test. So basically I added this in my arrange of my test if wanted my logging in the method I was testing to fire. Add something like this in your arrange or setup for you test class possibly:
[Test]
public void MyTest
{
//arrange
log4net.ILog log = log4net.LogManager.GetLogger(typeof(MyTestClass));
log4net.Config.XmlConfigurator.Configure();
}
Reading through https://msdn.microsoft.com/en-us/library/jj635153.aspx I have created a .RunSettings files with a few parameters similar to the example:
<TestRunParameters>
<Parameter name="webAppUrl" value="http://localhost" />
<Parameter name="webAppUserName" value="Admin" />
<Parameter name="webAppPassword" value="Password" />
</TestRunParameters>
I plan on having a .RunSettings file for each of our environments with appropriate URLs and credentials for running a CodedUI test on the specified RunSettings file's environment.
I can see that from command line to reference the Settings file I can run:
vstest.console myTestDll.dll /Settings:Local.RunSettings /Logger:trx
vstest.console myTestDll.dll /Settings:QA.RunSettings /Logger:trx
etc...
But I don't see any way that calls out how to actually utilize the TestRunParameters from within the codedUI test.
What I would like to do is set up test initializers that use the TestRunParameters to determine where to log in, and what credentials to use. Something like this:
[TestInitialize()]
public void MyTestInitialize()
{
// I'm unsure how to grab the RunSettings.TestRunParameters below
string entryUrl = ""; // TestRunParameters.webAppUrl
string userName = ""; // TestRunParameters.webAppUserName
string password = ""; // TestRunParameters.webAppPassword
LoginToPage(entryUrl, userName, password);
}
public void LoginToPage(string entryUrl, string userName, string password)
{
// Implementation
}
Information on how to reference the TestRunParameters is greatly appreciated!
EDIT
/// <summary>
/// Summary description for CodedUITest1
/// </summary>
[CodedUITest]
public class CodedUITest1
{
public static string UserName = string.Empty;
[ClassInitialize]
public static void TestClassInitialize(TestContext context)
{
UserName = context.Properties["webAppUserName"].ToString();
Console.WriteLine(UserName);
}
[TestMethod]
public void CodedUITestMethod1()
{
this.UIMap.RecordedMethod1();
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
}
// Rest of the default class - TestContext instantiation, UI map instantiation, etc
}
The exception I'm getting when running:
NullReference Exception
#williamfalconeruk I have updated my test class as above, but I am still getting the same error, any idea what I'm doing wrong?
For those that use Resharper with this issue, I discovered the fix (no need to disable Resharper):
Go to Visual Studio top menu -> Resharper -> Options
Find the Tools section, expand "Unit Testing"
Click on "MsTest". The checkbox should be on enabled, but the Test Settings file path below that may be blank. If it is, click on browse and select the runsettings file you want to use.
Click save, rebuild and try to run the tests, the parameters should now work.
Not sure why but simply selecting the Test Settings file from the Tests menu -> Test Settings does not actually work when using Resharper, so this file needs to be explicitly pointed to directly in the Resharper options.
I also came across this recently, as we wanted to move away from legacy environment variable usage. The solution provided below was suitable for our needs, but there may be a better one...
It turns out you can access these in the TestContext of a ClassInitialize method of your Test fixture. There is a Properties dictionary which has these parameters, and you could access the values here:
[ClassInitialize]
public static void TestClassinitialize(TestContext context)
{
var webAppUrl = context.Properties["webAppUrl"].ToString();
//other settings etc..then use your test settings parameters here...
}
Note: these are static so if you need access to this you may need to set up static properties to access within your Test code.
An alternative suggested is using a Data Driven Test approach.
Here's some basic info on data driven tests here which may also help:
https://msdn.microsoft.com/en-us/library/ms182527.aspx
As I said, the above solution suited our needs at a basic level.
UPDATE: see image below in response to test settings returning null...
This works for me (VS2017-pro):
namespace TestApp.Test
{
[TestClass]
public class UnitTest1
{
// This enables the runner to set the TestContext. It gets updated for each test.
public TestContext TestContext { get; set; }
[TestMethod]
public void TestMethod1()
{
// Arrange
String expectedName = "TestMethod1";
String expectedUrl = "http://localhost";
// Act
String actualName = TestContext.TestName;
// The properties are read from the .runsettings file
String actualUrl = TestContext.Properties["webAppUrl"].ToString();
// Assert
Assert.AreEqual(expectedName, actualName);
Assert.AreEqual(expectedUrl, actualUrl);
}
[TestMethod]
public void TestMethod2()
{
// Arrange
String expectedName = "TestMethod2";
// Act
String actualName = TestContext.TestName;
// Assert
Assert.AreEqual(expectedName, actualName);
}
}
}
Make sure to select the runsettings file you wish to use, here: Test -> Test Settings.
An alternative to disable Resharper is to enable MSTest support and select the test setting file on Resharper Options dialog (->Tools->Unit Testing->MsTest).
I was trying to do this exact thing as well. As many of you may know, running tests through MTM exposes some additional properties to the TestContext, including the name of the Run Settings used. I used this property as a "Foreign Key" of sorts for our test data, allowing us to specify environment URLs etc. without hardcoding them or using the incredibly lackluster "Data Driving" tools that come with out of the box testing.
Of course, there's no way to expose any run-time properties when executing tests as part of a BDT or release workflow besides what #kritner is attempting which microsoft describes HERE. However if you read the comments of that link you'll discover what you may be able to infer here:
You need to use VS 2013 R5 or VS 2015 to use this solution
It will only work for Unit Tests!
Those of us who are trying to execute UI or Load tests as part of a CI or CD workflow are completely screwed. You don't get any additional properties in testContext, even when executing a Plan/Suite with certain test configurations (not settings) created in MTM. #Adam may have been able to get this to work when running vs debugging, but that may have only worked with unit tests. Through CodedUI I've been unable to retrieve the properties without getting a NullReferenceException. Here's an example of the janky code I was using to investigate:
if (testContextInstance.Properties["__Tfs_TestConfigurationName__"] != null) //Exposed when run through MTM
{
TFSTestConfigurationName = testContextInstance.Properties["__Tfs_TestConfigurationName__"].ToString();
}
else TFSTestConfigurationName = "Local"; //Local
var configName = testContextInstance.Properties["configurationName"] ?? "No Config Found";
Trace.WriteLine("Property: " + configName);
And the XML of my .runsettings file:
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- Parameters used by tests at runtime. These are required as a substitute for TFS/MTM test settings.-->
<!-- File instructions: https://msdn.microsoft.com/en-us/library/jj635153.aspx#example -->
<!-- TFS instructions: https://blogs.msdn.microsoft.com/visualstudioalm/2015/09/04/supplying-run-time-parameters-to-tests/ -->
<TestRunParameters>
<Parameter name="configurationName" value="Local" />
</TestRunParameters>
</RunSettings>
And an excerpt from the .trx produced by the BDT workflow:
Property: No Config Found
For the NullReferenceException issue:
I was also facing the same issue recently and the solution to it is to have the latest update of Visual Studio 2013. Right now the latest update is Update 5. I am not sure which particular update fixes this issue. I applied Update 5 and was able to successfully access the TestRunParameters in the ClassInitialize method.
You can find the updates # https://support.microsoft.com/en-us/kb/2829760
So I had two machines, on one it was all working fine and on the other I was getting the exception. I investigated that the only difference is the Update of VS; applied it and that solved the problem. :)
With NUnit 3, I was able to find the properties in the runsettings file, using
TestContext.Parameters
So in this case it would be:
string entryUrl = TestContext.Parameters["webAppUrl"];
string username = TestContext.Parameters["webAppUserName"];
string password = TestContext.Parameters["webAppPassword"];
I was able to resolve this for Unit tests by disabling Resharper. Wish I could say the same for Coded UI tests.
Why dont you use Application settings?
you can then read them anywhere like
var yesICan= Properties.Settings.Default.IToldYou;
you can create Properties out from them, pretty much you can do a lot.
public string URL_WEBOFFICE
{
get
{
return Properties.Settings.Default.WEBOFFICE_URL.Replace("***", Properties.Settings.Default.SiteName);
}
}
I have a C# unit test project with application settings in the app.config file. I am testing a class that exists in a different project. That class depends on both, ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings.
The project that the class being tested resides in does not have an app.config file. I would have thought that because the class is being instantiated in the context of the unit test project that it would use the unit test project's app.config file. Indeed, that does seem to be the case for the connection string.
The class retrieves the connection string without any issues. However, when the class tries to retrieve any application settings the configuration manager always returns null. What is going on here?
Edit 1
I thought maybe it would be a good idea to try load some settings in the test project to see what happens. I tried to load the setting in the unit test immediately before calling the code that instantiates the class in the external project. Same result, nothing. I guess I can exclude the other project from the equation for the time being.
Here is an excerpt from my config file:
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyNamespace.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
...
<applicationSettings>
<MyNamespace.Properties.Settings>
<setting name="Bing_Key"
serializeAs="String">
<value>...</value>
</setting>
</MyNamespace.Properties.Settings>
</applicationSettings>
and here is how I am attempting to load the setting:
string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"];
Consider refactoring your code that accesses the config to use a wrapper. Then you can write mocks for the wrapper class and not have to deal with the importing of the configuration file for the test.
In a library that is common to both, have something like this:
public interface IConfigurationWrapper {
string GetValue(string key);
bool HasKey(string key);
}
Then, in your libraries that need to access config, inject an instance of this interface type into the class that needs to read config.
public class MyClassOne {
private IConfigurationWrapper _configWrapper;
public MyClassOne(IConfigurationWrapper wrapper) {
_configWrapper = wrapper;
} // end constructor
public void MethodThatDependsOnConfiguration() {
string configValue = "";
if(_configWrapper.HasKey("MySetting")) {
configValue = _configWrapper.GetValue("MySetting");
}
} // end method
} // end class MyClassOne
Then, in one of your libraries, create an implementation that depends on the config file.
public class AppConfigWrapper : IConfigurationWrapper {
public string GetValue(string key) {
return ConfigurationManager.AppSettings[key];
}
public bool HasKey(string key) {
return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant());
}
}
Then, in the code that calls your class.
//Some method container
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper());
dataClass.MethodThatDependsOnConfiguration();
Then in your test, you are free from dependency bondage. :) You can either create a fake version that implements IConfigurationWrapper and pass it in for your test, where you hard-code the return values from the GetValue and HasKey functions, or if you're using a mocking library like Moq:
Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>();
fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config.");
MyClassOne testObject = new MyClassOne(fakeWrapper.Object);
testObject.MethodThatDependsOnConfiguration();
Here is an article that covers the concept (albeit, for web forms, but the concepts are the same): http://www.schwammysays.net/how-to-unit-test-code-that-uses-appsettings-from-web-config/
You mentioned settings in the project properties. See if you can access the setting this way:
string test = Properties.Settings.Default.Bing_Key;
You may need to get the executing assembly of where the project settings file is defined, but try this first.
EDIT
When using Visual Studio's project settings file, it adds stuff to your app.config and creates the app.config if it is not present. ConfigurationManager CAN'T touch these settings! You can only get to these specific generated project.settings file from using the above static method. If you want to use ConfigurationManager, you will need to hand write your app.config. Add your settings to it like so:
<appSettings>
<add key="bing_api" value="whatever"/>
</appSettings>
If you're using .NET Core your problem could be a known issue caused by the fact that the test process runs as testhost.dll (or testhost.x86.dll), which means the runtime config file is expected to be named "testhost.dll.config" (or "testhost.x86.dll.config"), instead of the app.config output (ex: "MyLibrary.Tests.dll.config").
To fix it, add the code below to your project file (.csproj, etc) inside of root node <Project>. During build, two copies of app.config will be put in the output directory and named "testhost.dll.config" and "testhost.x86.dll.config", which will get your app settings working again. (You only need 1 of these files but it's safer to include both.)
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.x86.dll.config" />
</Target>
I recommend app.config only as a temporary solution. If you're like me you might have run into the problem while upgrading a .NET Framework project to .NET Core and needed a quick fix. But don't forget to look into the new, more elegant solutions provided by .NET Core for storing app settings.
And then he screamed "NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO".
Cite: I have a C# unit test project with application settings in the app.config file. I am testing a class that exists in a different project. That class depends on both, ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings.
You don't do this. EVER!!!! Why? because you have now created a dependency. Instead, use dependency injection so the class can do its work without having to peak into the configuration file that belongs to the application.