I have a Project where we have different kinds of unit tests in different DLLs. I want to know total number of unit tests in whole solution as well as the Test Category, Owner name, etc. using some VB/C# code.
Actually, I need to prepare report daily, where I need to show how many unit test are written by whom and under which category
I do not want to open Visual Studio to know this.
This is an example signature for one of the unit tests:
<TestMethod()> <Owner("OwnerName"), TestCategory("Category22")>
Public Sub TestName()
............
............
End Sub
Since the test methods are documented using .Net Framework attributes, you can use reflection to obtain the information you need. In VB.net, you can do it as follows.
'Imports System.Reflection
'Imports TestLibrary <- wherever the attributes are defined
Dim assy As Assembly = Assembly.LoadFrom(filename)
Dim owner As OwnerAttribute
Dim category As TestCategoryAttribute
For Each t As Type In assy.GetTypes()
For Each mi As MethodInfo In t.GetMethods(BindingFlags.Public Or BindingFlags.Instance)
If Not mi.GetCustomAttributes(GetType(TestMethodAttribute)).Count() = 0 Then
owner = mi.GetCustomAttribute(Of OwnerAttribute)()
category = mi.GetCustomAttribute(Of TestCategoryAttribute)()
System.Diagnostics.Debug.Print("{0} : Owner='{1}' Category='{2}'",
mi.Name, owner.OwnerName, category.CategoryName)
End If
Next
Next
You do have to add the test framework DLL as a reference to the project. filename is the full path to the compiled assembly (EXE, DLL, etc). I didn't include error checking for space reasons.
If your test method isn't public, or it's static you can get it by changing the binding flags to BindingFlags.NonPublic or BindingFlags.Static respectively. (More information is available in the documentation.)
Note that this method also works in C#
Assembly assy = Assembly.LoadFrom(filename);
OwnerAttribute owner = null;
TestCategoryAttribute category = null;
foreach(Type t in assy.GetTypes())
{
foreach (MethodInfo mi in t.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if (mi.GetCustomAttributes(typeof(TestMethodAttribute)).Count() != 0)
{
owner = mi.GetCustomAttribute<OwnerAttribute>();
category = mi.GetCustomAttribute<TestCategoryAttribute>();
System.Diagnostics.Debug.Print("{0} : Owner='{1}' Category='{2}'",
mi.Name, owner.OwnerName, category.CategoryName);
}
}
}
Related
I am currently developing a utility to help automate our report deployment process. Multiple files, in multiple folders, to multiple servers.
I am using the reportservice2010.asmx web service, and I am deploying my files to the server - so most of the way there.
My issue is that I have shared data sets and shared data sources, which are deployed to individual folders, separate to the report folders. When the deployment occurs the web service looks locally for the data source rather than in the data source folder, giving an error like:
The dataset ‘CostReduction’ refers to the shared data source ‘CostReduction’, which is not
published on the report server. The shared data source ‘CostReduction’ must be published
before this report can run.
The data source/set has been deployed and the report functions correctly but I need to suppress these error messages as they may be hiding other actual errors.
I can hard code a lookup that checks if the data source/set exists and manually filter them via that, but it seems very in-efficient. Is there any way I can tell the web service where to look for these files or another approach that other people have used?
I'm not looking at changing the reports so the data source is read from
/DataSources/DataSourceName
as there are lots of reports and that's not how our existing projects are configured.
Many thanks in advance.
I realize you are using VB, but perhaps this will give you a clue if you convert it from C# to VB, using one of the translators on the web.
Hopefully this will give you a lead in the right direction.
When All the reports in a particular folder, referred to here as the 'parent folder', all use the same Shared Data source, I use this to set all the reports to the same shared Data Source (in this case "/DataSources/Shared_New")
using GetPropertiesSample.ReportService2010;
using System.Diagnostics;
using System.Collections.Generic; //<== required for LISTS
using System.Reflection;
namespace GetPropertiesSample
{
class Program
{
static void Main(string[] args)
{
GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource("0_Contacts"); //<=== This is the parent folder
}
private static void GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource(string sParentFolder)
{
// Create a Web service proxy object and set credentials
ReportingService2010 rs = new ReportingService2010();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
CatalogItem[] reportList = rs.ListChildren(#"/" + sParentFolder, true);
int iCounter = 0;
foreach (CatalogItem item in reportList)
{
iCounter += 1;
Debug.Print(iCounter.ToString() + "]#########################################");
if (item.TypeName == "Report")
{
Debug.Print("Report: " + item.Name);
ResetTheDataSource_for_a_Report(item.Path, "/DataSources/Shared_New"); //<=== This is the DataSource that I want them to use
}
}
}
private static void ResetTheDataSource_for_a_Report(string sPathAndFileNameOfTheReport, string sPathAndFileNameForDataSource)
{
//from: http://stackoverflow.com/questions/13144604/ssrs-reportingservice2010-change-embedded-datasource-to-shared-datasource
ReportingService2010 rs = new ReportingService2010();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
string reportPathAndName = sPathAndFileNameOfTheReport;
//example of sPathAndFileNameOfTheReport "/0_Contacts/207_Practices_County_CareManager_Role_ContactInfo";
List<ReportService2010.ItemReference> itemRefs = new List<ReportService2010.ItemReference>();
ReportService2010.DataSource[] itemDataSources = rs.GetItemDataSources(reportPathAndName);
foreach (ReportService2010.DataSource itemDataSource in itemDataSources)
{
ReportService2010.ItemReference itemRef = new ReportService2010.ItemReference();
itemRef.Name = itemDataSource.Name;
//example of DataSource i.e. 'itemRef.Reference': "/DataSources/SharedDataSource_DB2_CRM";
itemRef.Reference = sPathAndFileNameForDataSource;
itemRefs.Add(itemRef);
}
rs.SetItemReferences(reportPathAndName, itemRefs.ToArray());
}
}
To Call it I use this in the 'Main' Method:
GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource("0_Contacts");
In this case "0_Contacts" is the parent folder, itself located in the root directory, that contains all the reports for which I want to reset their DataSources to the new Shared DataSource. Then that Method calls the other method "ResetTheDataSource_for_a_Report" which actually sets the DataSource for the report.
In a Eclipse plugin it's easy to get the current project(IProject) if there's an editor opened, you just need to use this snippet:
IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
IFileEditorInput input = (IFileEditorInput)editor.getEditorInput();
IFile file = input.getFile();
IProject project = file.getProject();
But, is there a way to get the project if I don't have any kind of file opened in the editor?, i.e: imagine that you have a plugin that adds an option when you right click a project, and if you click this option a dialog window is launched, how can I print the project name in this dialog?
For menu items and the like which use a 'command' with a 'handler' you can use code in the handler which is something like:
public class CommandHandler extends AbstractHandler
{
#Override
public Object execute(ExecutionEvent event) throws ExecutionException
{
ISelection sel = HandlerUtil.getCurrentSelection(event);
if (sel instanceof IStructuredSelection)
{
Object selected = ((IStructuredSelection)sel).getFirstElement();
IResource resource = (IResource)Platform.getAdapterManager().getAdapter(selected, IResource.class);
if (resource != null)
{
IProject project = resource.getProject();
...
}
}
return null;
}
}
What do you mean by "The current project"? Getting a specific project will always require some way of uniquely identifying that specific project.
If by current project you mean that the project is open, then that's not a good criterion for uniqueness (in the general case), since multiple projects can be open at the same time.
A guarantee of uniquely defining a project is by getting a reference to a resource contained by that project. For example, this can be done through the editor input, as you state, or trough a selection, as greg pointed out.
If you have the project's name, then you can use IWorkspaceRoot#getProject(String), but I assume that's not the case. Still, for completeness:
ResourcesPlugin.getWorkspace().getRoot().getProject("MyProject");
You could also get a list of all projects, and iterate over that list to check for a property that you know the project has (or the projects have). See the example below. Of course, this again doesn't guarantee uniqueness in the general case, since there can be multiple projects that satisfy the criteria. That's why I used Lists in the example.
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
List<IProject> openProjects = new ArrayList<>();
List<IProject> myNatureProjects = new ArrayList<>();
for(IProject project : projects)
{
if(project.isOpen())
openProjects.add(project);
if(project.hasNature("MyNatureId")
myNatureProjects.add(project);
}
I have a misunderstanding somewhere with the Entity Framework. This code is from my unit testing:
Public Sub UpdateRosterLinkTest()
Dim target As PlayerAdmin = New PlayerAdmin()
target.PlayerAdminManager = playerAdminTestManager
target.Team = playerAdminTestManager.GetAirForceMensBB()
playerAdminTestManager.resetRosterLink(target)
Assert.IsNull(target.Team.RosterLink)
Dim playerAdmin As PlayerAdmin = New PlayerAdmin()
playerAdmin.TeamId = 12434
playerAdmin.RosterLink = "Roster Link"
playerAdmin.UpdateRosterLink()
Dim team As DAL.Team = playerAdminTestManager.GetAirForceMensBB()
Assert.AreEqual("Roster Link", team.RosterLink)
End Sub
I'm creating a PlayerAdmin, which is a model class. target.Team is an Entity object. What I do is reset the RosterLink field in the Team just to make sure our test starts out at the same place. Then I call the UpdateRosterLink() function. That looks like:
Function UpdateRosterLink() As Integer
If (PlayerAdminManager Is Nothing) Then
PlayerAdminManager = New PlayerAdminManager()
End If
Team = PlayerAdminManager.GetTeamByTeamId(TeamId)
Team.RosterLink = RosterLink
Dim numberOfChanges As Integer = PlayerAdminManager.SaveChanges()
Return numberOfChanges
End Function
When I run this code, I can see the changes saved to the SQL Server this pulls from (RosterLink = Roster Link, like I set in the unit test).
However, my unit test is failing, because team.RosterLink is still Nothing. The function GetAirForceMensBB() returns the Team with TeamId = 12434:
Function GetAirForceMensBB() As DAL.Team
Return (From team In Container.Teams Where team.TeamId = 12434).SingleOrDefault
End Function
I'm sure I'm using the entity framework incorrectly and it probably has something to do with the fact that I am calling the PlayerAdminTestManager in different places, but I don't understand why. Although, I set the PlayerAdminManager to be the PlayerAdminTestManager. PlayerAdminTestManager extends PlayerAdminManager, fyi.
Why is team.RosterLink not showing the update from UpdateRosterLink?
Thanks
EDIT
Container is my ObjectContext. This is how I access the information stored in the database. Container.Teams represents my Teams table.
The problem was I was referencing different instantiations of the Container (each manager created its own). Thus, the entity items were not attached to anything.
Doh!
How would I go about extracting the IL code for classes that are generated at runtime by reflection so I can save it to disk? If at all possible. I don't have control of the piece of code that generates these classes.
Eventually, I would like to load this IL code from disk into another assembly.
I know I could serialise/deserialise classes but I wish to use purely IL code. I'm not fussed with the security implications.
Running Mono 2.10.1
Or better yet, use Mono.Cecil.
It will allow you to get at the individual instructions, even manipulating them and disassembling them (with the mono decompiler addition).
Note that the decompiler is a work in progress (last time I checked it did not fully support lambda expressions and Visual Basic exception blocks), but you can have pretty decompiled output in C# pretty easily as far as you don't hit these boundary conditions. Also, work has progressed since.
Mono Cecil in general let's you write the IL to a new assembly, as well, which you can then subsequently load into your appdomain if you like to play with bleeding edge.
Update I came round to trying this. Unfortunately I think I found what problem you run into. It turns out there is seems to be no way to get at the IL bytes for a generated type unless the assembly happened to get written out somewhere you can load it from.
I assumed you could just get the bits via reflection (since the classes support the required methods), however the related methods just raise an exception The invoked member is not supported in a dynamic module. on invocation. You can try this with the code below, but in short I suppose it means that it ain't gonna happen unless you want to f*ck with Marshal::GetFunctionPointerForDelegate(). You'd have to binary dump the instructions and manually disassemble them as IL opcodes. There be dragons.
Code snippet:
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Reflection.Emit;
using System.Reflection;
namespace REFLECT
{
class Program
{
private static Type EmitType()
{
var dyn = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Emitted"), AssemblyBuilderAccess.RunAndSave);
var mod = dyn.DefineDynamicModule("Emitted", "Emitted.dll");
var typ = mod.DefineType("EmittedNS.EmittedType", System.Reflection.TypeAttributes.Public);
var mth = typ.DefineMethod("SuperSecretEncryption", System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static, typeof(String), new [] {typeof(String)});
var il = mth.GetILGenerator();
il.EmitWriteLine("Emit was here");
il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
il.Emit(System.Reflection.Emit.OpCodes.Ret);
var result = typ.CreateType();
dyn.Save("Emitted.dll");
return result;
}
private static Type TestEmit()
{
var result = EmitType();
var instance = Activator.CreateInstance(result);
var encrypted = instance.GetType().GetMethod("SuperSecretEncryption").Invoke(null, new [] { "Hello world" });
Console.WriteLine(encrypted); // This works happily, print "Emit was here" first
return result;
}
public static void Main (string[] args)
{
Type emitted = TestEmit();
// CRASH HERE: even if the assembly was actually for SaveAndRun _and_ it
// has actually been saved, there seems to be no way to get at the image
// directly:
var ass = AssemblyFactory.GetAssembly(emitted.Assembly.GetFiles(false)[0]);
// the rest was intended as mockup on how to isolate the interesting bits
// but I didn't get much chance to test that :)
var types = ass.Modules.Cast<ModuleDefinition>().SelectMany(m => m.Types.Cast<TypeDefinition>()).ToList();
var typ = types.FirstOrDefault(t => t.Name == emitted.Name);
var operands = typ.Methods.Cast<MethodDefinition>()
.SelectMany(m => m.Body.Instructions.Cast<Instruction>())
.Select(i => i.Operand);
var requiredTypes = operands.OfType<TypeReference>()
.Concat(operands.OfType<MethodReference>().Select(mr => mr.DeclaringType))
.Select(tr => tr.Resolve()).OfType<TypeDefinition>()
.Distinct();
var requiredAssemblies = requiredTypes
.Select(tr => tr.Module).OfType<ModuleDefinition>()
.Select(md => md.Assembly.Name as AssemblyNameReference);
foreach (var t in types.Except(requiredTypes))
ass.MainModule.Types.Remove(t);
foreach (var unused in ass.MainModule
.AssemblyReferences.Cast<AssemblyNameReference>().ToList()
.Except(requiredAssemblies))
ass.MainModule.AssemblyReferences.Remove(unused);
AssemblyFactory.SaveAssembly(ass, "/tmp/TestCecil.dll");
}
}
}
If all you want is the IL for your User class, you already have it. It's in the dll that you compiled it to.
From your other assembly, you can load the dll with the User class dynamically and use it through reflection.
UPDATE:
If what you have is a dynamic class created with Reflection.Emit, you have an AssemblyBuilder that you can use to save it to disk.
If your dynamic type was instead created with Mono.Cecil, you have an AssemblyDefinition that you can save to disk with myAssemblyDefinition.Write("MyAssembly.dll") (in Mono.Cecil 0.9).
VS WCF integration has nice option "Reuse types in refrenced assemblies". The problem is that I need the same but for the current assembly. Some of the types are already defined in my assembly and I need to reuse them.
Usage scenario:
I have assembly, and have TypeA here.
I add Service Reference ot it, and one of the methods returns type that is fully compatible with TypeA(properties, name).
Add Service Reference generates proxy, but it recreate new TypeA within.
On the step 3 I need proxy that will return TypeA. Not new TypeA.
If I understand what you want to do, then it's an scenario I commonly run into, and well, WCF does have a decent answer to: Just don't use SvcUtil / WS Service Reference wizards.
If you have most of the contract classes already defined in your client side (be that because you have a shared assembly or because you have equivalent classes defined on your project), you might as well just go to the next step and either import the complete service contract in code form or simply redefine it on the client side.
There's nothing that forces you to use svcutil and friends, just define your interface and either use the channel model directly (i.e. ChannelFactory<T> and friends) or, if you prefer to use proxy classes, just create your own ClientBase<T>-derived class. It's really very easy and it will save you trouble in the long run.
There is an easy way to share types between client and service, just by adding reference to shared type assembly to your client BEFORE adding the service reference.
You can find the detailed scenario and sample project there:
http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html
I had the same problem, whereby I wanted a test harness to point to a couple of services. Each service would have datacontracts in common.
What needs to be done:
Use svcutil with /t:metadata on each url.
Rename all the generated files with something unique for the service (e.g. Rename lala.xsd to 1_lala.xsd)
Copy all generated files to a single location
Use svcutil with *.xsd .wsdl /out:output.cs /namespace:,MySpecialNamespace to generate ALL service contracts and datacontracts to a single file.
If you want to be crafty: use the following T4 template:
<## template language="C#v4.0" hostspecific="True"#>
<## import namespace="System.Diagnostics" #>
<## import namespace="System.IO" #>
<#=GetGeneratedCode(
"http://localhost/Service/Service1.svc",
"http://localhost/Service/Service2.svc",
"http://localhost/Service/Service3.svc",
"http://localhost/Service/Service4.svc"
)#>
<#+
const string _svcutil = #"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\svcutil.exe";
private string GetGeneratedCode(params string[] urls)
{
var tmp = GetTemporaryDirectory();
foreach (var url in urls)
{
GetMetadata(url, tmp);
}
RunSvcutil(tmp, "*.wsdl *.xsd /out:output.cs /namespace:*," + Path.GetFileNameWithoutExtension(Host.TemplateFile));
var result = File.ReadAllText(Path.Combine(tmp, "output.cs"));
return result;
}
private static void RunSvcutil(string workingFolder, string arguments)
{
var processInfo = new ProcessStartInfo(_svcutil);
processInfo.Arguments = arguments;
processInfo.WorkingDirectory = workingFolder;
var p = Process.Start(processInfo);
p.WaitForExit();
}
private static void GetMetadata(string url, string destination)
{
var workingFolder = GetTemporaryDirectory();
RunSvcutil(workingFolder, string.Format("/t:metadata \"{0}\"", url));
foreach (var filename in Directory.GetFiles(workingFolder))
{
File.Copy(filename, Path.Combine(destination, Path.GetFileNameWithoutExtension(url) + "_" + Path.GetFileName(filename)));
}
}
private static string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}
#>