How can I check if project is a Test Project? (NUnit, MSTest, xUnit) - visual-studio

I want to check if selected project (I have source code) is a TestProject for one of the following framework: NUnit, MSTest, xUnit.
For MSTest it is simple. I can check .csproj and tag. If I have there {3AC096D0-A1C2-E12C-1390-A8335801FDAB} than it means it is Test project.
The problem are NUnit and xUnit. I can check for this cases references in .csproj. If I have nunit.framework or xunit it will be obvious. But I wondering if is possible to check this in diffrent way.
Do you know different way to recognize test projects?

One of the way is to check if assembly contains test methods. Attributes for test methods are as following:
NUnit: [Test]
MSTest: [TestMethod]
xUnit.net: [Fact]
Iterate over assemblies and check if assembly contains class with test methods. Example code:
bool IsAssemblyWithTests(Assembly assembly)
{
var testMethodTypes = new[]
{
typeof(Xunit.FactAttribute),
typeof(NUnit.Framework.TestAttribute),
typeof(Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute)
};
foreach (var type in assembly.GetTypes())
{
if (HasAttribute(type, testMethodTypes)) return true;
}
return false;
}
bool HasAttribute(Type type, IEnumerable<Type> testMethodTypes)
{
foreach (Type testMethodType in testMethodTypes)
{
if (type.GetMethods().Any(x => x.GetCustomAttributes(testMethodType, true).Any())) return true;
}
return false;
}
You can also add more assumptions:
check if classes contains TestFixture method,
check if classes / test methods are public.
EDIT:
If you need to use C# Parser, here is a sample of NRefactory code for checking if a .cs file contains classes with tests:
string[] testAttributes = new[]
{
"TestMethod", "TestMethodAttribute", // MSTest
"Fact", "FactAttribute", // Xunit
"Test", "TestAttribute", // NUnit
};
bool ContainsTests(IEnumerable<TypeDeclaration> typeDeclarations)
{
foreach (TypeDeclaration typeDeclaration in typeDeclarations)
{
foreach (EntityDeclaration method in typeDeclaration.Members.Where(x => x.EntityType == EntityType.Method))
{
foreach (AttributeSection attributeSection in method.Attributes)
{
foreach (Attribute atrribute in attributeSection.Attributes)
{
var typeStr = atrribute.Type.ToString();
if (testAttributes.Contains(typeStr)) return true;
}
}
}
}
return false;
}
Example of NRefactory .cs file parsing:
var stream = new StreamReader("Class1.cs").ReadToEnd();
var syntaxTree = new CSharpParser().Parse(stream);
IEnumerable<TypeDeclaration> classes = syntaxTree.DescendantsAndSelf.OfType<TypeDeclaration>();

I would look for usage of the attributes representing each framework to see which is which.
Use reflection to find classes/methods with the appropriate attribute types (e.g. Test/TestFixture)
This answer has an example that you can modify to meet your needs:
get all types in assembly with custom attribute

Check NuGet references in *.csproj for specific nuggets used for testing.

Related

Embed Interop Types property is missing in CLR Project

I have a CLR Empty Project (.NET Framework 4.6.2) I've noticed that the Embed Interop Types is not present in the References Properties, I couldn't find a workaround, is there a way to turn it on? It looks like it's only available on C#.
I come up with the following workaround:
Add the particular assembly you want to embed into your project, right click on it, select Properties then set Item Type to Compiled Managed Resource and put the following snippet at the first lines inside the main:
[System::STAThread]
int main()
{
System::AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(&loadEmbeddedAssembly);
}
And at somewhere there:
System::Reflection::Assembly^ loadEmbeddedAssembly(System::Object^ sender, System::ResolveEventArgs^ args) {
System::Reflection::AssemblyName^ assemblyName = gcnew System::Reflection::AssemblyName(args->Name);
System::String^ resourceName = assemblyName->Name + ".dll";
System::IO::Stream^ stream = System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceStream(resourceName);
array<System::Byte>^ assemblyData = gcnew array<System::Byte>((unsigned long)stream->Length);
try {
stream->Read(assemblyData, 0, assemblyData->Length);
}
finally {
if (stream != nullptr) delete stream;
}
return System::Reflection::Assembly::Load(assemblyData);
}

Resolve actual Reference path using Microsoft.Build.Evaluation

I'm doing some introspection and analysis of csproj files using the Microsoft.Build.Evaluation tools in a small C# console app. I want to locate the actual location of Reference items, using the same heuristics as MSBuild itself ie the locations described here. I'm heading towards auto conversion of build artifacts into packages, similar to what's outlined on the JetBrains blog here
The only examples I can find expect the HintPath to be correct, for example this project, and I know there are some HintPaths that are not currently correct, I don't want to trust them. This project very close what I'm trying to do, with the added complication that I want to use real resolution behaviour to find dependencies.
I have an instance of a Microsoft.Build.Evaluation.Project object for my csproj, and I can't see any methods available on it that could exersize the resolution for me. I think what I'm hoping for is a magic Resolve() method for a Reference or a ProjectItem, a bit like this method.
I can probably find an alternative by constraining my own search to a set of limited output paths used by this build system, but I'd like to hook into MSBuild if I can.
The reference resolution is one of the trickiest parts of MSBuild. The logic of how assemblies are located is implemented inside the a standard set of tasks:
ResolveAssemblyReference, ResolveNativeReference, etc. The logic is how this works is very complicated, you can see that just by looking at number of possible parameters to those tasks.
However you don't need to know the exact logic to find the location of referenced files. There are standard targets called "ResolveAssemblyReferences", "ResolveProjectReferences" and some others more specialized for native references, COM references. Those targets are executed as part of the normal build. If you just execute those targets separately, you can find out the return values, which is exactly what you need. The same mechanism is used by IDE to get location of refereces, for Intellisense, introspection, etc.
Here is how you can do it in code:
using Microsoft.Build.BuildEngine;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;
class Program
{
static int Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: GetReferences.exe <projectFileName>");
return -1;
}
string projectFileName = args[0];
ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(projectFileName);
var result = manager.Build(
new BuildParameters()
{
DetailedSummary = true,
Loggers = new List<ILogger>() { logger }
},
new BuildRequestData(projectInstance, new string[]
{
"ResolveProjectReferences",
"ResolveAssemblyReferences"
}));
PrintResultItems(result, "ResolveProjectReferences");
PrintResultItems(result, "ResolveAssemblyReferences");
return 0;
}
private static void PrintResultItems(BuildResult result, string targetName)
{
var buildResult = result.ResultsByTarget[targetName];
var buildResultItems = buildResult.Items;
if (buildResultItems.Length == 0)
{
Console.WriteLine("No refereces detected in target {0}.", targetName);
return;
}
foreach (var item in buildResultItems)
{
Console.WriteLine("{0} reference: {1}", targetName, item.ItemSpec);
}
}
}
Notice, the engine is called to invoke specific targets in the project. Your project usually does not build, but some targets might be invoked by pre-requisite targets.
Just compile it and will print a sub-set of all dependencies. There might be more dependencies if you use COM references or native dependencies for your project. It should be easy to modify the sample to get those as well.

How do you use a Typescript Unit Test to test Typescript in Visual Studio?

I'm trying to write a unit test in Typescript to test a Typescript class, but when the test is run, it doesn't know anything about the class.
I'm using Typescript (1.4) with Node Tools for Visual Studio (2013) and the test helpfully appears in Test Explorer. When run it fails with "Reference Error: ClassC not defined."
The class I'm testing:
class ClassC {
functionF() {
return 42;
}
}
Generated Javascript:
var ClassC = (function () {
function ClassC() {
}
ClassC.prototype.functionF = function () {
return 42;
};
return ClassC;
})();
//# sourceMappingURL=ClassC.js.map
The test (created from template Add -> new Item... -> TypeScript UnitTest file):
/// <reference path="ClassC.ts" />
import assert = require('assert');
export function classCTest() {
var foo: ClassC = new ClassC();
var result: number = foo.functionF();
assert.equal(result, 42);
}
Generated Javascript:
var assert = require('assert');
function classCTest() {
var foo = new ClassC();
var result = foo.functionF();
assert.equal(result, 42);
}
exports.classCTest = classCTest;
//# sourceMappingURL=ClassC_tests.js.map
When looking at the generated Javascript for the test it becomes obvious why the error occurs. It does not contain the necessary definition for ClassC. I thought including the reference path would help, but it obviously didn't.
How do I get the unit test to know about the class?
I thought including the reference path would help, but it obviously didn't.
export class ClassC and then use an import statement instead of a reference comment. Also compile with the compiler flag --module commonjs.
More : https://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1 and http://basarat.gitbooks.io/typescript/content/docs/project/external-modules.html

VS2010 Code Coverage Not Accurate

I'm using Visual Studio 2010 Ultimate SP1. I have around 225 unit tests in my project, and they are all passing. One of those tests, however, reports 0% code coverage for the method it hits. When debugging, I can step through and see that it hits every line of the method. Yet in the code coverage report, it shows that the method isn't covered at all. All other tests and methods work just fine with regards to code coverage.
I've tried the following with no success:
Moved the method being tested into another class.
Made the method
static vs. non-static.
Moved the test to another class.
Deleted all of my .testsetting files and recreated them from scratch
Wrote a different test to exercise the same method, with the same results
restarted VS
rebooted
In case it matters, the method was in the Global.asax file. However, I moved it to another class and it made no difference.
Any ideas?
Here is the method being tested.
public void LogError(ILoggingService loggingService, IController controller)
{
if (loggingService == null)
throw new ArgumentNullException("loggingService");
if (controller == null)
throw new ArgumentNullException("controller");
Exception ex = Server.GetLastError();
loggingService.LogException(ex.Message, ex.StackTrace, ApplicationName.VoucherLog, UserInfo.UserName);
HttpException httpException = ex as HttpException;
if (httpException == null)
{
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "HttpError";
Server.ClearError();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
controller.Execute(rc);
}
}
The first 4 lines, where the exceptions are thrown, are hit by other tests and show up in the code coverage statistics. The remainder of the method is hit by the following test (as verified by debugging through it and seeing that each and every line is, in fact, executed), but does not show up in code coverage stats. Here is the test:
[TestMethod]
[HostType("Moles")]
public void LogError()
{
DMVCommon.ApplicationName expectedApplication = DMVCommon.ApplicationName.VoucherLog;
string expectedUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
NotImplementedException expectedException = null;
System.Web.Moles.MHttpServerUtility.AllInstances.GetLastError = (System.Web.HttpServerUtility server) =>
{
return expectedException;
};
System.Web.Moles.MHttpApplication.AllInstances.ContextGet = (System.Web.HttpApplication application) =>
{
return MvcMockHelpers.FakeHttpCurrentContext();
};
try
{
throw new NotImplementedException();
}
catch (NotImplementedException exc)
{
expectedException = exc;
using (MvcApplication app = new MvcApplication())
{
bool called = false;
Mock<ILoggingService> mockLoggingService = new Mock<ILoggingService>();
mockLoggingService.Setup(a => a.LogException(expectedException.Message, expectedException.StackTrace, expectedApplication, expectedUser)).Callback(() => called = true);
Mock<IController> mockController = new Mock<IController>();
app.LogError(mockLoggingService.Object, mockController.Object);
mockController.Verify(a => a.Execute(It.IsAny<System.Web.Routing.RequestContext>()), Times.Exactly(1));
Assert.IsTrue(called);
}
}
}
This happens probably because of your usage of Moles - As the runner loads the assembly, Moles takes over and profiles the assembly instead of the coverage profiler.
There has been known integration issues with coverage tools and Moles -
In order for two .Net profilers (Moles & coverage) to work together they have to implement specific support for each other.
Try to run without Moles and see what happens...
Also see this as a similar example.

Entity Framework Designer Extension Not loading

I created a small extension for the EF designer that adds a new property to the property window. I did this using a vsix project (new project -> c# -> extensibility -> vsix project). When I hit F5 the experimental VS instance starts up. I create a new project, add an entity data model and add an entity. However, my break points never get hit and I don't see the property. Any ideas as to what I might be doing wrong?
public class AggregateRootValue
{
internal static XName AggregateRootElementName = XName.Get("AggregateRoot", "http://efex");
private readonly XElement _property;
private readonly PropertyExtensionContext _context;
public AggregateRootValue(XElement parent, PropertyExtensionContext context)
{
_property = parent;
_context = context;
}
[DisplayName("Aggregate Root")]
[Description("Determines if an entity is an Aggregate Root")]
[Category("Extensions")]
[DefaultValue(true)]
public string AggregateRoot
{
get
{
XElement child = _property.Element(AggregateRootElementName);
return (child == null) ? bool.TrueString : child.Value;
}
set
{
using (EntityDesignerChangeScope scope = _context.CreateChangeScope("Set AggregateRoot"))
{
var element = _property.Element(AggregateRootElementName);
if (element == null)
_property.Add(new XElement(AggregateRootElementName, value));
else
element.SetValue(value);
scope.Complete();
}
}
}
}
[Export(typeof(IEntityDesignerExtendedProperty))]
[EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)]
public class AggregateRootFactory : IEntityDesignerExtendedProperty
{
public object CreateProperty(XElement element, PropertyExtensionContext context)
{
var edmXName = XName.Get("Key", "http://schemas.microsoft.com/ado/2008/09/edm");
var keys = element.Parent.Element(edmXName).Elements().Select(e => e.Attribute("Name").Value);
if (keys.Contains(element.Attribute("Name").Value))
return new AggregateRootValue(element, context);
return null;
}
}
EDIT: I put the code on Github: https://github.com/devlife/Sandbox
EDIT: After Adding the MEF component to the manifest as suggested, the extension still never loads. Here is a picture of the manifest:
So the answer, as it turns out, is in how I setup my project. I put both classes inside the project which produces the VSIX file. By simply moving those classes into another project and setting that project as the MEF Component in the manifest (and thus copying the assembly) it worked like a charm!
For VS2012, it is only needed to add Solution as MEF component also. Just add whole solution as MEF component also.
Then it works surprisingly fine.
It seems the dll built by your project isn't automatically included in the generated VSIX package, and VS2013 doesn't give you options through the IDE to change this (that I can work out, anyway).
You have to manually open the project file and alter the XML. The property to change is IncludeAssemblyInVSIXContainer.
Seen here: How to include VSIX output in it's package?

Resources