使用反射测试MEF部件 [英] Test MEF parts using reflection
问题描述
我有一个使用MEF的应用程序,我正在尝试为插件编写集成测试。
我的代码是: -
< pre lang =c#>
public string Run()
{
IFunction IUT = null; string Wanted =NewUser;
foreach(Lazy< IFunction,IFunctionData> func in functions)
{
if(func.Metadata.FunctionName == Wanted)IUT = func.Value;
}
bool res = false;
res = TestOne(IUT);
if(res)TestTwo();
如果(res)返回Pass - NewUser Test;
返回失败 - NewUser测试;
}
//普通新用户OK
private bool TestOne(IFunction IUT)
{
bool res = false;
//设置VM属性
var VM = IUT.GetType();
PropertyInfo prop = VM.GetProperty(UserName); prop.SetValue(prop,Smith);
MethodInfo Method = VM.GetMethod(CreateNewUser);
// ...
// ...
返回res;
}
IFunction部分都是ViewModels,Run方法找到正确的OK。
我想做的是设置此VM的UserName属性,然后运行Create方法
我陷入了设置VM属性并运行方法的方法,我所拥有的不是工作。
我尝试了什么:
谷歌搜索想出了单位测试建议,但我需要测试与应用程序其余部分的集成
您不需要使用MEF反射,只需输出&导入以共享数据 - 数据可以存在于主应用程序之外的DLL / EXE中。只要MEF可以编写,数据就会可见。这就是我们在另一个 MEF解决方案 [ ^ ]其中请求了插件系统的反射和当DLL / EXE被放入主应用程序的文件夹时,插件会自动加载。
因此,答案是创建一个类来单独保存用户详细信息class(repository),使用PartCreationPolicy(CreationPolicy.Shared)
定义Export
。这将创建一个静态/共享对象。以下是一个示例:
public interface IUserRepository
{
string UserName { get ; set ; }
}
[导出( typeof (IUserRepository)),
PartCreationPolicy(CreationPolicy.Shared)]
public class UserRepository:ObservableBase,IUserRepository
{
private string userName = ** Not Set **;
public string UserName
{
get = > userName;
set = > 设置( ref userName, value );
}
}
注意:上面的代码不是线程安全的。如果你需要,我会留给你实现。
这是ObservableBase
类:
public abstract class ObservableBase:INotifyPropertyChanged
{
public void 设置< TValue>( ref TValue字段,TValue newValue,[CallerMemberName] 字符串 propertyName = < span class =code-string> )
{
if (EqualityComparer< TValue> .Default.Equals(field, default (TValue))||!field.Equals(newValue))
{
field = newValue;
PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged ;
public bool IsInDesignMode = > DesignerProperties.GetIsInDesignMode( new DependencyObject());
}
现在你import
UserRepository
:
[导入( typeof (IUserRepository),RequiredCreationPolicy = CreationPolicy.Shared)]
public IUserRepository Repo { get ; set ; }
...现在,只要使用上述Import
,就会共享用户数据:
Repo.UserName = MainUser;
您无需进行反射编码,因为它全部由MEF处理。享受!
PS:是的,MEF正在使用反射,所以你不必! ;)
I have an application using MEF and am trying to write integration tests for the Plug-ins. The code I have is:- <pre lang="c#"> public string Run() { IFunction IUT = null; string Wanted = "NewUser"; foreach (Lazy<IFunction, IFunctionData> func in functions) { if (func.Metadata.FunctionName == Wanted) IUT = func.Value; } bool res = false; res = TestOne(IUT); if (res) TestTwo(); if (res) return "Pass - NewUser Test"; return "Fail - NewUser Test"; } // Normal New User OK private bool TestOne(IFunction IUT) { bool res = false; // Set up the VM properties var VM = IUT.GetType(); PropertyInfo prop=VM.GetProperty("UserName");prop.SetValue(prop, "Smith"); MethodInfo Method = VM.GetMethod("CreateNewUser"); //... //... return res; }
The IFunction parts are all ViewModels and the Run method finds the correct one OK.
What I want to do is set the UserName property of this VM and then run the Create method
I am stuck on a way to set the VM properties and run the method, what I have does not work.
What I have tried:
Google searches came up with Unit test suggestions but I need to test integration with the rest of the application
You don't need to use reflection with MEF, you simply Export & Import to share data - the data can exist in a DLL/EXE outside of the main app. So long as MEF can compose, the data will be visible. This is what we did in another MEF Solution[^] where reflection was requested for a plugin system and the plugins automatically load when the DLL/EXE is dropped into the main app's folder.
So, the answer is to create a class to hold your user details in a seperate class (repository), define theExport
with aPartCreationPolicy(CreationPolicy.Shared)
. This will create a static/shared object. Here is an example:
public interface IUserRepository { string UserName { get; set; } } [Export(typeof(IUserRepository)), PartCreationPolicy(CreationPolicy.Shared)] public class UserRepository : ObservableBase, IUserRepository { private string userName = "**Not Set**"; public string UserName { get => userName; set => Set(ref userName, value); } }
NOTE: The above code is not thread safe. I'll leave that up to you to implement if you require that.
Here is theObservableBase
class:
public abstract class ObservableBase : INotifyPropertyChanged { public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "") { if (EqualityComparer<TValue>.Default.Equals(field, default(TValue)) || !field.Equals(newValue)) { field = newValue; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; public bool IsInDesignMode => DesignerProperties.GetIsInDesignMode(new DependencyObject()); }
Now youimport
theUserRepository
:
[Import(typeof(IUserRepository), RequiredCreationPolicy = CreationPolicy.Shared)] public IUserRepository Repo { get; set; }
... and the user data is now shared whereever the aboveImport
is used:
Repo.UserName = "MainUser";
No reflection coding by you is required as it is all handled by MEF. Enjoy!
PS: Yes, MEF is using reflection so you don't have to! ;)
这篇关于使用反射测试MEF部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!