使用反射测试MEF部件 [英] Test MEF parts using reflection

查看:137
本文介绍了使用反射测试MEF部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用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 the Export with a PartCreationPolicy(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 the ObservableBase 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 you import the UserRepository:

[Import(typeof(IUserRepository), RequiredCreationPolicy = CreationPolicy.Shared)]
public IUserRepository Repo { get; set; }


... and the user data is now shared whereever the above Import 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆