Reflection for unit testing internal properties - c#

I have a public class(TargetContainerDto) that has 2 internal properties. An enum and a type that contains a value from that enum.
I'm trying to unit test the type, but I'm having problems.
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
internal TargetContainerType Type { get; set; }
This is my reflection code in my test class
public void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
public TargetContainerDto setTypeTo(TargetContainerDto t, int val)
{
setType(t, val);
return t;
}
TargetContainerDto has more properties than Type, but they are public so testing them is fine. The iconURL is a string defined in TargetContainerDto depending on what the type is. Here is my Testmethod:
public void DefaultSubGroupIcon()
{
var o1 = new TargetContainerDto
{
Id = 1234,
DistinguishedName = "1.1.1.1",
SubGroup = "test",
};
setType(o1, 3);
Assert.AreEqual(o1.IconUrl, "/App_Themes/Common/AppControl/Images/workstation1.png");
}
I call setTypeTo in test method when I need to set the typevalue, but I'm getting a MethodAccessException. I think it's because I don't have access to the enum. How can I access the enum through reflection?
Thanks

Mark your assembly with the InternalsVisibleTo attribute and you don't need to use reflection in your test dll.
e.g. in the AssemblyInfo.cs file in your application dll add the following line:
[assembly:InternalsVisibleTo("TestAssembly")]
see here for more details.

You asking the wrong question. A better question would be:
How do I stop testing internal state of the class?
But, if you utterly need this, there are couple of ways described in this relevant SO answer

I agree with other comments that you should try to redesign to avoid testing internal state, however I did try your code and it works fine for me (.Net 4 on VS2012).
My class library under test looks like this:
using System;
namespace ClassLibrary
{
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
public class TargetContainerDto
{
internal TargetContainerType Type
{
get;
set;
}
public void Print()
{
Console.WriteLine(Type);
}
}
}
And the test program (a Console app) looks like this:
using System;
using System.Reflection;
using ClassLibrary;
namespace Demo
{
internal class Program
{
private static void Main(string[] args)
{
var test = new TargetContainerDto();
setType(test, 1);
test.Print();
}
public static void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
}
}
This prints out Group, as expected. If we can identify the differences between this and your actual code, we may be able to find the problem.

Related

Custom Attributes and Accessing Them In C#

I am working on an application that stores data in the ConfigurationManager.AppSettings file, and I am wanting to implement it in a different way than how I do right now. Currently, I have an interface (see below) that each class with saveable traits needs to implement, then call the static save methods from my Config class (example below). I don't like the coupling between my Config class and the class with the saveable data, so my ideal would be to have an attribute that indicates a property should be saved. Then, instead of calling the SaveData or LoadData functions in my manager class, I would call a function that sets/saves all the attributed properties. This seems similar to how [Serializeable] works in default C#, so I imagine it's possible somehow. However, most of my searches have been fruitless. Any ideas on how to implement something like this?
Interface
Example
Reflection is what you're looking for.
Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them.
Assuming that you're only interested in properties, you can use typeof or GetType to get an instance of System.Type. You can then call GetProperties to get an IEnumerable<PropertyInfo>. PropertyInfo has an Attributes property that you can use to retrieve the attributes for that property. You can also use an instance of PropertyInfo to retrieve the value of the property.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property)]
public class MyAttribute : Attribute
{
}
public class Foo
{
[My]
public string Bar { get; set; }
public string Baz { get; set; }
[My]
public string Id { get; set; }
}
public static class Utilities
{
public static IEnumerable<PropertyInfo> GetPropertiesWithMyAttribute(object obj)
{
return obj.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(pi => pi.CustomAttributes.Any(ca => ca.AttributeType == typeof(MyAttribute)));
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo()
{
Bar = "Bar_Value",
Baz = "Baz_Value",
Id = "Id_Value"
};
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
Console.WriteLine($"{pi.Name}: {pi.GetMethod.Invoke(foo, null).ToString()}");
}
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
pi.SetMethod.Invoke(foo, new object[] { $"{pi.Name}_Value_Reflection" });
}
Console.WriteLine(foo.Bar);
Console.WriteLine(foo.Baz);
Console.WriteLine(foo.Id);
Console.ReadKey();
}
}
Of course, this example only string properties. You're going to have to figure out some way to deal with properties that aren't strings; for example you haven an ObservableCollection in your example.

xUnit adding Trait to CollectionDefinition

In xUnit and Visual Studio, I would like to group tests marked with the [Collection("DB")] attribute in the Test Explorer. I can group test by the [Trait("Collection", "DB")] attribute only. Is there any way how to assign a specific Trait to all tests with [Collection("DB")] attribute?
Update: I have added xUnit issue #799.
Copied from http://mac-blog.org.ua/xunit-category-trait/.
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
using XunitCategoriesSample.Traits;
namespace XunitCategoriesSample.Traits
{
public class CategoryDiscoverer : ITraitDiscoverer
{
public const string KEY = "Category";
public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
{
var ctorArgs = traitAttribute.GetConstructorArguments().ToList();
yield return new KeyValuePair<string, string>(KEY, ctorArgs[0].ToString());
}
}
//NOTICE: Take a note that you must provide appropriate namespace here
[TraitDiscoverer("XunitCategoriesSample.Traits.CategoryDiscoverer", "XunitCategoriesSample")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CategoryAttribute : Attribute, ITraitAttribute
{
public CategoryAttribute(string category) { }
}
}
namespace XunitCategoriesSample
{
public class Class1
{
[Fact]
[Category("Jobsearcher")]
public void PassingTest()
{
Assert.Equal(4, Add(2, 2));
}
[Fact]
[Category("Employer")]
public void FailingTest()
{
Assert.Equal(5, Add(2, 2));
}
int Add(int x, int y)
{
return x + y;
}
}
}
NOTICE you must provide right namespaces in TraitDiscoverer attribute.
But here is more, lets make even more specialized attributes:
public class JobsearcherTraitDiscoverer : ITraitDiscoverer
{
public const string VALUE = "Jobsearcher";
public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
{
yield return new KeyValuePair<string, string>(CategoryDiscoverer.KEY, VALUE);
}
}
[TraitDiscoverer("XunitCategoriesSample.Traits.JobsearcherTraitDiscoverer", "XunitCategoriesSample")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class JobsearcherTraitAttribute : Attribute, ITraitAttribute
{
public JobsearcherTraitAttribute()
{
}
}
So from now on you will be able to just type [JobsearcherTrait]
Links:
https://github.com/xunit/xunit/issues/394 - discussion about why TraitAttribute was marked as sealed
https://github.com/xunit/samples.xunit/tree/master/TraitExtensibility - sample by xunit how to make custom attributes
https://github.com/wespday/CategoryTraits.Xunit2 - one more sample
https://github.com/xunit/xunit/blob/47fdc2669ae6aa28f6d642e202840193dfc7dbd7/test/test.xunit.execution/Common/TraitHelperTests.cs - xunit test sample of implementing custom attributes
In the Xunit.Sdk.ITraitDiscoverer interface GetTraits method's argument 'traitAttribute' is having actual attribute value, but unfortunately the is no direct way to get it as Xunit.Abstractions.IAttributeInfo has no getter which is weird. Here is just another solution without calling GetConstructorArguments()
Enum for exact categories we need
public enum Category
{
UiSmoke,
ApiSmoke,
Regression
}
Custom attribute definition
[TraitDiscoverer("Automation.Base.xUnit.Categories.CategoryDiscoverer", "Automation.Base")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class TestCategoryAttribute : Attribute, ITraitAttribute
{
public string Category { get; }
public TestCategoryAttribute(Category category)
{
Category = category.ToString();
}
}
And here is the category resolver/discoverer
public sealed class CategoryDiscoverer : ITraitDiscoverer
{
public const string Key = "Category";
public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
{
var category = traitAttribute.GetNamedArgument<string>(Key);
yield return new KeyValuePair<string, string>(Key, category);
}
}
Here is the catch we need to know exact property name in the TestCategoryAttribute type, in discoverer its defined using Key constant.
Anyway, both GetConstructorArguments() and GetNamedArgument() are based on reflection, while discoverer is executed per each test once being run which is not that super-fast.
You can do this:
enum Collection {
DB,
File,
// Others
}
And later at class or method level:
[Trait(nameof(Collection), nameof(Collection.DB))]
Clean and simple

Properties in a particular order

Using reflection I have a tool that gets the properties of a class:
foreach (MemberInfo member in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
WriteValue(streamWriter, member.Name);
}
Is there a way to ask "GetProperties" to return MemberInfo's in the order they are defined in the class. I seriously doubt it, but thought I'd ask.
class Person
{
public int Id { get; set; }
public int Age { get; set; }
}
I'd like to get MemberInfo's in this order then: Id, Age
[Caution: use at your own discresion as these are obviously Microsoft's impl details, which may change in future releases]
Update: Mono seems to work too
I've observed consitent behaviour using MS compilers since v3.5 when I stumbled upon this:
using System;
using System.Linq;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
typeof(Test).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.OrderBy(member => member.MetadataToken).ToList()
.ForEach(member => Console.WriteLine(member.Name));
Console.ReadLine();
}
}
public class Test
{
public int SecondProperty { get; set; }
public int FirstProperty { get; set; }
}
}
No, for auto-properties there isn't. You can get methods in order of declaration using debug symbols, and since property getters are methods, you can (with some work) obtain a list of properties with explicit getters (or setters) in order of declaration, but the getters of auto-properties have no source code and thus no debug symbols to indicate their location. As for CLI metadata, the compiler is not obliged to put them in order of declaration, and as reflection relies exclusively on metadata, it cannot be used for this purpose.

How to share a static method amongst several class

I'd like to start with something like this:
class A { ... }
class B { ... }
class C { ... }
Where A, B and C have a static method MyName.
Then I could do:
Console.WriteLine(A.MyName());
Console.WriteLine(B.MyName());
Console.WriteLine(C.MyName());
Then after I should be able to do something like this.
foreach(var type in new[] { typeof(A), typeof(B), typeof(C)) {
??? Console.WriteLine(t.MyName());
}
How could I do that?
I'd also like to be able to do the following (but that may be impossible):
??? x = new A();
Console.WriteLine(x.MyName());
x = new B();
Console.WriteLine(x.MyName());
What you're trying to do here is associate Metadata with a type, which can be queried if you know the type. The standard practice for doing this is to use Custom Attributes. You can query these attributes in a type-safe way and extract the associated information for each attribute. They are quite flexible in how you specify their inheritance and whether you can apply more than one of the same attribute type. They can also be applied to other things besides classes, like properties or fields, which can be handy.
Here's a simple demo program (the null check isn't strictly necessary here, but just demonstrating how you check whether an attribute actually exists.) Note that the extension method that provides a generic GetCustomAttribute was only added in .NET 4.5. Prior versions will require you to use a non-generic version and cast it to the appropriate attribute type.
class Program
{
static void Main(string[] args)
{
var types = new[] {typeof(A), typeof(B), typeof(C)};
foreach (var type in types)
{
var attribute = type.GetCustomAttribute<NameAttribute>();
if (attribute != null)
Console.WriteLine(attribute.Name);
}
Console.ReadLine();
}
public sealed class NameAttribute : Attribute
{
public string Name { get; private set; }
public NameAttribute(string name)
{
Name = name;
}
}
[Name("A Name")]
public class A
{
}
[Name("B Name")]
public class B
{
}
[Name("C Name")]
public class C
{
}
}
In order to share some static member between classes you need to inherit from base class which will contain static member:
public class Base
{
public static string MyName() { return "Bob"; }
}
public class A : Base
{
}
public class B : Base
{
}
You can't do what you are trying in your foreach loop, because variable t has type Type and Type do not have any MyName properties. You should use reflection to get MyName value:
Console.WriteLine(A.MyName()); // Bob
Console.WriteLine(B.MyName()); // Bob
foreach(var type in new[] { typeof(A), typeof(B) })
{
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;
var method = type.GetMethod("MyName", flags);
Console.WriteLine(method.Invoke(null, null));
}
This code prints Bob for both types.

Why does GetProperty fail to find it?

I'm trying to use reflection to get a property from a class. Here is some sample code of what I'm seeing:
using System.Reflection;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
PropertyInfo[] tmp2 = typeof(TestClass).GetProperties();
PropertyInfo test = typeof(TestClass).GetProperty(
"TestProp", BindingFlags.Public | BindingFlags.NonPublic);
}
}
public class TestClass
{
public Int32 TestProp
{
get;
set;
}
}
}
When I trace through this, this is what I see:
When I fetch all properties using GetProperties(), the resulting array has one entry, for property TestProp.
When I try to fetch TestProp using GetProperty(), I get null back.
I'm a little stumped; I haven't been able to find anything in the MSDN regarding GetProperty() to explain this result to me. Any help?
EDIT:
If I add BindingFlags.Instance to the GetProperties() call, no properties are found, period. This is more consistent, and leads me to believe that TestProp is not considered an instance property for some reason.
Why would that be? What do I need to do to the class for this property to be considered an instance property?
Add BindingFlags.Instance to the GetProperty call.
EDIT: In response to comment...
The following code returns the property.
Note: It's a good idea to actually make your property do something before you try to retrieve it (VS2005) :)
using System.Reflection;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
PropertyInfo[] tmp2 = typeof(TestClass).GetProperties();
PropertyInfo test = typeof(TestClass).GetProperty(
"TestProp",
BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic);
Console.WriteLine(test.Name);
}
}
public class TestClass
{
public Int32 TestProp
{
get
{
return 0;
}
set
{
}
}
}
}
Try to add the following tag:
System.Reflection.BindingFlags.Instance
EDIT: This works (at least to me)
PropertyInfo test = typeof(TestClass).GetProperty("TestProp", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine(test.Name);
You need to specify whether it is static or an instance (or both) too.

Categories