Fix: Exception "Mixed mode assembly is built against version ‘v2.0.50727’ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.", when code is executed in a Microsoft Visual Studio 2012 test project.

When using an old version of LeadTools I encountered an exception during the execution of a Microsoft Visual Studio 2012 test. Mixed mode assembly is built against version ‘v2.0.50727’ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information. This error was fixed following the steps on http://blog.kristandyson.com/2012/05/encountering-systemiofileloadexception.html.

 

  1. Close Microsoft Visual Studio 2012 (and IIS express)
  2. On Windows 8, start Notepad.exe as an administrator
  3. Open the file [C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.executionengine.x86.exe.config]
  4. Add and save:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="Extensions" />     
    </assemblyBinding>
  </runtime>
  <system.diagnostics>
    <switches>
      <add name="TpTraceLevel" value="0" />
    </switches>
  </system.diagnostics>
  <appSettings>
    <!–<add key="ExecutionThreadApartmentState" value ="MTA"/>–>
    <!–<add key="TraceLogMaxFileSizeInKb" value ="10240"/>–> 

    <!– MsTest Adapter Specific AppSettings –>
    <add key="TestProjectRetargetTo35Allowed" value="true" />
   </appSettings>
   <startup useLegacyV2RuntimeActivationPolicy="true">
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
   </startup>

</configuration>

Running javascript and typescript unit tests in Microsoft Visual Studio 2012 with Chutzpah

To unit test my JavaScript files in Microsoft Visual Studio 2012, side by side mine C# unit tests, I use Chutzpah.

Chutzpah comes with 2 Microsoft Visual Studio 2012 extensions:

1. Chutzpah Test Adapter for Visual Studio 2012, allows you to run QUnit / Jasmine javascript test files side by side C# unit tests in the test explorer or continuous build process.

2. Chutzpah – A JavaScript Test Runner, allows you to run individual QUnit / Jasmine JavaScript test files in Microsoft Visual Studio 2010 and 2012 by right clicking a test file and choosing "".

 

In Microsoft Visual Studio 2012

– Tools > Extensions and Updates…

– Install both plugins and restart Microsoft Visual Studio 2012

 

image

 

Create a new UnitTest project:

 

image

 

Enable "Run Tests after build"

(The "Play" button found at the top of the Test Explorer")

Now when you press CTRL + SHIFT + B the project will be build and all tests will execute.

 

image 

 

TIP: Never use CTRL + S to save your file, just use CTRL + SHIFT + B.

Now you can see the C# unit test "TestMethod1" succeeded.

 

QUnit for ASP.NET MVC

Right click unit test project and click Manage NuGet Packages…

Click install.

 

image

 

Add Code.js and Test.js

The Code.js file will contain the JavaScript code we want to test.

The Test.js  file will contain the JavaScript test code written, by using the QUnit test framework.

 

Code.js

image

 

Test.js

Reference qunit and the Code.js file to get code completion in your test code.

 

image

 

Code completion in JavaScript in Microsoft Visual Studio 2012 unit test file

 

image

 

 

Run C# and JavaScript unit tests side by side in the Test Explorer

By pressing CTRL + SHIFT + B

image

 

Run only JavaScript unit test file

If you only want to run the QUnit test, right click on the JavaScript Test.js file and choose "Run JS Tests".

 

image

 

If you want to run JavaScript unit tests by pressing a keyboard shortcut, you need to install

image

 

Then you can bind a shortcut to the ProjectAndSolutionsContextMenus.Project.RunJSTests command to run JS tests.

(http://matthewmanela.com/blog/chutzpah-1-1-0-released/)

 

image

TIP: Reassign keyboard shortcuts, when using TDD with Microsoft Visual Studio and TestDriven.Net

If you are using TDD in Microsoft Visual Studio 2010 and apply that red – green – refactor thingie, you want your tests to execute as fast as possible. Well MSTEST in Microsoft Visual Studio 2010 is known to be a snail, so for TDD in Microsoft Visual Studio 2010 you probably want to use external tools like ReSharper, TestDriven.Net  etc.

 

To further improve the speed I reassign the keyboard shortcuts:

  • CTRL + Q to run the current test(s) in context without debugger.
  • CTRL + W to run the current test(s) in context with debugger.

image

 

Notes

  • By the way, in Microsoft Visual Studio 2012 there is a tremendous performance improvement in running unit test, so you might want to look at that.
  • An other tip: don’t use CTRL + S (to save code), instead use CTRL + Q to save, compile and run tests on your code at once.

How to do JavaScript unit testing from C# with MSTest and JSTest

I wanted to run regular MSTest unit test written in C# to assert JavaScript code. There are several ways to accomplish this, but in this case I use JSTest.

Just add JSTest to your C# testproject with NuGet, now you can write tests like:

 

Test class

using JSTest;
using JSTest.ScriptLibraries;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestProject1.Helpers;
namespace TestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var script = new TestScript();
// Arrange: Append the JavaScript code to test.
string scriptContents = (new AssemblyHelper().GetContentsEmbededResourceFile("TestProject1.MvcApplication1.Scripts.Person.js"));
script.AppendBlock(scriptContents);
// Arrange: Append the JSTest asser library, so we can assert the test code.
script.AppendBlock(new JsAssertLibrary());
// Append "Act" JavaScript code.
script.AppendBlock("var person1 = new Person('John Do', 32, 'Software Engineer');");
// Assert.
script.RunTest(@"assert.equal('Jonh Do test', person1.sayName());");
}
}
}

Running this test within Microsoft Visual Studio 2010 will result in a passed test.

 

JavaScript code to test

function Person(name, age, job)
{
var privateField1 = 'test';
this.name = name;
this.age = age;
this.job = job;
this.privilegedMethod = function () { return privateField1; }
};
Person.prototype.sayName = function ()
{
return this.name + ' ' + this.privilegedMethod();
};

Notes

– The privilegedMethod is used to access private fields on the Person class.

– You can set breakpoints in the JavaScript code!!

C# helper class

using System;
using System.IO;
using System.Reflection;
namespace TestProject1.Helpers
{
public class AssemblyHelper
{
/// <summary>
/// Read the contents of an embededresourcefile with the given name.
/// </summary>
/// <param name="resourceName">Name of the resource.</param>
/// <returns></returns>
public string GetContentsEmbededResourceFile(string resourceName)
{
if (string.IsNullOrWhiteSpace(resourceName)) { throw new ArgumentNullException("resourceName"); }
string contents = string.Empty;
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
using (var reader = new StreamReader(stream))
{
contents = reader.ReadToEnd();
}
return contents;
}
}
}

Microsoft Visual Studio 2010

image

How to redirect the standard console output, to assert logmessages written by log4net.

By using a log4net ConsoleAppender, you can write all log messages in your application to the console. These message will show up in the Microsoft Visual Studio output window. I needed a way to redirect the messages written to the console, so I could verify if the correct messages were send to the console. For this task I redirected the standard console output in my unit test:

 

Code

using System;
using System.IO;
using System.Text;
using log4net;
using log4net.Config;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Save original console output writer.
TextWriter originalConsole = Console.Out;
// Configure log4net based on the App.config
XmlConfigurator.Configure();
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
// Redirect all Console messages to the StringWriter.
Console.SetOut(writer);
// Log a debug message.
ILog logger = LogManager.GetLogger("Unittest logger");
logger.Debug("This is a debug message");
}
// Get all messages written to the console.
string consoleOutput = string.Empty;
using (var reader = new StringReader(builder.ToString()))
{
consoleOutput = reader.ReadToEnd();
}
// Assert.
string expected = "This is a debug message" + Environment.NewLine;
Assert.AreEqual(expected, consoleOutput);
// Redirect back to original console output.
Console.SetOut(originalConsole);
}
}
}

App.config

 

<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

Microsoft Visual Studio

 

image

 

I used NuGet to add a reference to the latest log4net build.

How to change the *.mdf and *.ldf location of an online Microsoft SQL Server LocalDb database in a Microsoft Visual Studio 2010 test.

For testing purposes it is possible to copy a new localdb database to your output directory and start using this localdb database. For more information see my previous post: https://www.roelvanlisdonk.nl/?p=2607

It is possible that a previous tests run did not cleanup it’s copy of the localdb database. Now if you want to attach an new localdb database with the same name, the attach will fail. There are several options you have to fix this error. I decided to just "re-use" the existing database, just changing the *.mdf and *.ldf file location.

 

The following code can help you do just that:

using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace Test.Research
{
/// <summary>
/// Tests in this class are only used to analyse and research code.
/// It is not intended to contain real integration tests.
/// </summary>
[TestClass]
public class RliResearchTester
{
/// <summary>
/// Changes the *.mdf and *.ldf file location for the given LocalDb database, when it exists.
/// </summary>
/// <remarks>
/// It expects the mdf file name to be in the format [DatabaseName.mdf].
/// It expects the ldf file name to be in the format [Databasename_log.ldf].
/// It expects the old mdf file name to be equal to the new mdf file name (only the file location will change).
/// It expects the old ldf file name to be equal to the new ldf file name (only the file location will change).
/// </remarks>
[TestMethod]
public void ChangeMdfAndLdfLocationForExistingLocalDb()
{
string dataSource = @"(localdb)\V11.0";
string databaseName = "MyReserachDb";
string folderContainingNewDatabaseFiles = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string oldMdfFilePath = GetMdfFilePath(dataSource, databaseName);
if (!string.IsNullOrWhiteSpace(oldMdfFilePath))
{
ModifyDatabaseFilePaths(dataSource, databaseName, folderContainingNewDatabaseFiles);
}
}
/// <summary>
/// Gets the full physical mdf filepath, based on the supplied data soruce (Servername\Instancename) and database name.
/// </summary>
/// <param name="dataSource">SQL Server instance in the format (ServerName\InstanceName)</param>
/// <param name="databaseName">Name of the database.</param>
/// <returns>
/// Databse found:     Returns the full physical mdf filepath.
/// Databse not found: Returns null.
/// </returns>
/// <remarks>
/// Uses windows authentication to connect.
/// This function does not take into account, the fact that a mdf file name can be different, then the [DatabaseName.mdf].
/// </remarks>
public string GetMdfFilePath(string dataSource, string databaseName)
{
string result = null;
string mdfName = databaseName;
using (var connection = new SqlConnection(string.Format(@"Data Source=""{0}"";Initial Catalog=master;Integrated Security=True;", dataSource)))
using (var command = new SqlCommand("select top 1 physical_name from sys.master_files where name = @MdfName", connection))
{
command.Parameters.Add(new SqlParameter("MdfName", mdfName));
connection.Open();
result = command.ExecuteScalar() as string;
}
return result;
}
/// <summary>
/// Modifies the *.mdf and *.ldf database file locations of an existing online database.
/// </summary>
/// <param name="dataSource">SQL Server instance in the format (ServerName\InstanceName)</param>
/// <param name="databaseName">Name of the database.</param>
/// <param name="folderContainingNewDatabaseFiles">The folder containing new database files.</param>
/// <remarks>
/// - Uses windows authentication to connect.
/// - Drops all existing database connections, by using [with rollback immediate] on the [set offline].
/// - Forces the database to use the new files, by using [set offline] and [set online].
/// - It expects the mdf file name to be in the format [DatabaseName.mdf].
/// - It expects the ldf file name to be in the format [Databasename_log.ldf].
/// - It expects the old mdf file name to be equal to the new mdf file name (only the file location will change).
/// - It expects the old ldf file name to be equal to the new ldf file name (only the file location will change).
/// </remarks>
public void ModifyDatabaseFilePaths(string dataSource, string databaseName, string folderContainingNewDatabaseFiles)
{
string mdfName = databaseName;
string ldfName = string.Format("{0}_log", databaseName);
string newMdfFileLocation = Path.Combine(folderContainingNewDatabaseFiles, string.Format("{0}.mdf", mdfName));
string newLdfFileLocation = Path.Combine(folderContainingNewDatabaseFiles, string.Format("{0}.ldf", ldfName));
string query = string.Format(@"
alter database {0} modify file (name = {1}, filename = '{3}');
alter database {0} modify file (name = {2}, filename = '{4}');
alter database {0} set offline with rollback immediate;
alter database {0} set online;", 
new string[] { databaseName, mdfName, ldfName, newMdfFileLocation, newLdfFileLocation });
using (var connection = new SqlConnection(string.Format(@"Data Source=""{0}"";Initial Catalog=master;Integrated Security=True;", dataSource)))
using (var command = new SqlCommand(query, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
}

How to use content files from another project in a Visual Studio unit test, by using DeploymentItems.

 

To access a file from another project in a Microsoft Visual Studio unit test, without specifying the absolute path, you can use DeploymentItems.

 

DeploymentItems

DeploymentItems are files that will be copied to the output folder of the test. Microsoft Visual Studio tests are not run in the bin directory, but for each test a new directory is created, like: C:\Temp\Rli.Common\TestResults\rlisdonk_L084 2012-03-13 09_30_34\Out. DeploymentItems will be copied to this directory.

 

Enable DeploymentItems

Double click on the Solution Item > Local.testsettings in the Solution Explorer > Click on Deployment > check the "Enable deployment" checkbox > Apply > Close.

image

 

Add DeploymentItems

Now you can add DeploymentItems to your TestClass or TestMethod:

using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Rli.TestProject
{
[TestClass]
[DeploymentItem(@"Rli.Common\Settings.xml")]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(System.IO.File.Exists("Settings.xml"));
}
}
}

The file [Settings.xml] in the Rli.Common project, can now be accessed in the unit test "UnitTest1.TestMethod1" in the Microsoft Visual Studio test project "Rli.TestProject".

 

image

 

 

Notes

  • The relative path used in [DeploymentItem(@"Rli.Common\Settings.xml")]  is relative to the Solution Folder!
  • If you want the file to be copied for all tests, you can add the file to the deployment files in the Local.testsettings. If you add the file to the deployment files, you don’t have to specify the DeploymetItem attribute on your TestClass or TestMethod, because the files will automatically be deploy to the test output folder:
  • image
  • If you only want to use a content file from another project, the test project does not have to reference the other project.
  • Adding files as linked content files (Project > Add Existing Item… > browse to the file, select it and click on Add As Link) and setting the file property "Copy to Output Directory" property to "Copy Always" will not work in this case. You will need to use DeploymentItems.
  • If you are using TFS with build templates, make sure the setting "TestSettings File" is set to a testsettings file that has Deployment files set to enabled. As testsettings file you can use, the Local.testsettings edited above.

image

Resolving: Validator.TryValidateObject always returns true in a UnitTest, when using a MetadataType class in Entity Framework 4

When you use a metadata class in Entity Framework the registration between the entity and the metadata class is not registered for all Microsoft Visual Studio Project types (the "test project class library" for example).

I found the solution at: http://stackoverflow.com/questions/2657358/net-4-rtm-metadatatype-attribute-ignored-when-using-validator. It demonstrates registring all metadata classes in an assembly.

 

Solution

Add the following class, to the assembly that contains the Entity Framework model (*.edmx) and the metadata classes:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
/// <summary>
/// Metadata classes are not always automatically registered, for example in a UnitTest classlibrary.
/// This class can be used to register all metadata classes find in this assembly.
/// 
/// Registration will only be done once.
/// </summary>
public static class MetadataTypesRegister
{
private static bool _installed = false;
private static readonly object InstalledLock = new object();
/// <summary>
/// Register all metadata classes found in this assembly.
/// Registration will only be done once.        
/// </summary>
public static void InstallForAssembly()
{
if (_installed)
{
return;
}
lock (InstalledLock)
{
if (_installed)
{
return;
}
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (MetadataTypeAttribute attrib in type.GetCustomAttributes(typeof(MetadataTypeAttribute), true))
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(type, attrib.MetadataClassType), type);
}
}
_installed = true;
}
}
}

 

In entity framework, you define metadata attributes in an internal sealed metadata "buddy" class like:

[MetadataType(typeof(CustomerMetadata))]
public partial class Customer
{
internal sealed class CustomerMetadata
{
[Required(ErrorMessage = "Id is required")]
public Int32 Id { get; set; }
[Required(ErrorMessage = "Name is required")]
public String Name { get; set; }
[DataType(DataType.EmailAddress)]
public String Email { get; set; }
[RegularExpression("^[0-9]{4}[a-z|A-Z]{2}$")]
public String Zipcode { get; set; }
}
}

You can unit test the metadata attributes by using the following unit test class.

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Research.Dal2;
using System.ComponentModel.DataAnnotations;
[TestClass]
public class CustomerTester
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext) 
{
MetadataTypesRegister.InstallForAssembly();
}
[TestMethod]
public void ValidateZipcodeTest()
{
var customer = new Research.Dal2.Customer();
customer.Zipcode = "this is a wrong zipcode";
var vc = new ValidationContext(customer, null, null) { MemberName = "Zipcode" };
var validationResults = new List<ValidationResult>();
// Validate only the zip code.
bool isValidZipCode = Validator.TryValidateProperty(customer.Zipcode, vc, validationResults);
Assert.IsFalse(isValidZipCode);
// Validate the whole Customer entity.
bool isValidCustomer = Validator.TryValidateObject(customer, vc, validationResults, true);
Assert.IsFalse(isValidCustomer);
}
}