更新使用共享功能的两种常用功能的最佳方式 [英] Best way to Update Two common functions to use shared function

查看:137
本文介绍了更新使用共享功能的两种常用功能的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

微软单元测试向导创建,如果你需要从另外一个项目来测试一个非公开的属性存取对象。在我的单元测试创​​建的辅助功能,因此,我不重复同样的code只是在每一个单元测试方法。目前我有两个测试,是几乎相同的除了一个需要一个标准的公共对象,以及其他需要访问器版本。由于访问器是基于公共对象,我应该能有一个功能。我原以为我可以使用泛型来完成一个简单的演员。但在<一个href="http://stackoverflow.com/questions/12998916/update-two-common-functions-to-use-generics">posting 我发现这是一个很多工作,包括具有更新底层对象的问题。我的问题是另一种方式来减少这些冗余的方法只能有一个功能用铸件(或其他)的方法呢?

下面是现有的两个功能:

  //常见的函数来创建标准帐户对象的新测试记录
内部静态无效CreateAccount(出帐帐,布尔saveToDatabase)
{
    日期时间创建= DateTime.Now;
    字符串createdBy = _testUserName;

    帐户=新帐户(创建,createdBy);

    account.Notes = Utilities.RandomString(1000);

    如果(saveToDatabase)
        account.Create();
}

//常见的功能来创建Account_Accessor一个新的测试记录
内部静态无效CreateAccount(出Account_Accessor账户,布尔saveToDatabase)
{
    日期时间创建= DateTime.Now;
    字符串createdBy = _testUserName;

    帐户=新Account_Accessor(创建,createdBy);

    account.Notes = Utilities.RandomString(1000);

    如果(saveToDatabase)
        account.Create();
}
 

我有二十几这些单元测试和实物平均有10个物业,我已经简化了的例子在这里。

下面是单元测试API创建(同样,我已经降低下来,以简化的例子),访问​​code:

 使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用系统;
使用System.Collections.ObjectModel;
使用System.Data这;

命名空间NameHere.Bll
{
    [遮蔽(NameHere.Bll.Account)]
    公共类Account_Accessor:ProjectBase_Accessor&LT;帐户&GT;
    {
        受保护的静态PrivateType m_privateType;

        公共Account_Accessor(PrivateObject值);
        [遮蔽(男星@ 2)]
        公共Account_Accessor(DateTime的创建,串createdBy);

        [遮蔽(_笔记)
        公共字符串_notes {获得;组; }

        公共静态Account_Accessor ​​AttachShadow(对象的值);

        [遮蔽(创建@ 0)]
        公众覆盖无效创建();
    }
}

使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用系统;
使用System.ComponentModel;
使用System.Linq.Ex pressions;

命名空间NameHere.Bll
{
    [遮蔽(NameHere.Bll.ProjectBase`1)]
    公共类ProjectBase_Accessor&LT; T&GT; :BaseShadow,INotifyPropertyChanged的
    {
        受保护的静态PrivateType m_privateType;

        公共ProjectBase_Accessor(PrivateObject值);

        [遮蔽(创建)
        公众的DateTime创建{获得;组; }
        公共静态PrivateType ShadowedType {获得; }

        [遮蔽(add_PropertyChanged @ 1)]
        公共无效add_PropertyChanged(PropertyChangedEventHandler值);
        公共静态ProjectBase_Accessor&LT; T&GT; AttachShadow(对象的值);

        [遮蔽(创建@ 0)]
        公共虚拟无效创建();
    }
}
 

解决方案

现在的问题是,即使访问类公开相同的方法和属性,因为它屏蔽了该班,还有就是访问和原来的类之间没有通用接口。 Account_Accessor从BaseShadow继承,客户从别的继承。它们是完全无关的类型,只要编译器而言,不分配兼容,所以这将是困难的,通过每个实例成一个共同的例行程序。

如果你能迫使Account_Accessor类来实现这也是由客户实现的接口类型,那么你可以通过每个实例到该走接口类型作为参数的函数。像这样的:

 内部静态IAccount SetupAccount(IAccount账户,布尔saveToDatabase)
{
//做账的设置在这里 - 不是建设
}

//调用:构造实例,然后传递给常用功能
VAR账户=新帐户(A,B);
SetupAccount(帐号,真实);
 

如果你想有一个共同的例程,太多,把特定类型的包装中的共同作用前方施工帐户实例是足够复杂的:

 内部静态IAccount CreateAccount(布尔saveToDatabase)
{
    VAR账户=新帐户(A,B);
    返回SetupAccount(帐户,saveToDatabase);
}

内部静态IAccount CreateAccountAccessor(布尔saveToDatabase)
{
    VAR账户=新Account_Accessor(A,B);
    返回SetupAccount(帐户,saveToDatabase);
}
 

有一点你无法逃避的是:有人的地方必须承诺构建哪个实例。即使你熬下来到各地传递的类型和使用 Activator.CreateInstance(),有人已经承诺选择使用哪些类型。

在该实例构造,并且这两种类型实现一个共同的接口,那么所有的常用功能需要关心的是通用接口。

The Microsoft Unit Test Wizard creates Accessor objects if you need to test a non-public property from another project. Inside my Unit Tests I create helper functions so that I don't repeat the same code just in every Unit Test method. Currently I have two tests that are almost identical except one takes a standard public object, and the other takes the Accessor version. Since the Accessor is based on the public object I should be able to have one function. I had assumed that I could use Generics to accomplish with a simple cast. But after posting the question I discovered it was a lot more work, including having to update the underlying objects. My question is another approach to reduce these redundant methods to only having one function using casting (or another) approach?

Here are the existing two functions:

// Common function to create a new test record with standard Account object
internal static void CreateAccount(out Account account, bool saveToDatabase)
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = new Account(created, createdBy);

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

// Common function to create a new test record with Account_Accessor
internal static void CreateAccount(out Account_Accessor account, bool saveToDatabase)
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = new Account_Accessor(created, createdBy);

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

I have two dozen of these Unit Tests and the real objects have an average of 10 properties, I've simplified the examples here.

Here is the Accessor code that the Unit Test API creates (again, I have reduced it down to simplify the example):

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.ObjectModel;
using System.Data;

namespace NameHere.Bll
{
    [Shadowing("NameHere.Bll.Account")]
    public class Account_Accessor : ProjectBase_Accessor<Account>
    {
        protected static PrivateType m_privateType;

        public Account_Accessor(PrivateObject value);
        [Shadowing(".ctor@2")]
        public Account_Accessor(DateTime created, string createdBy);

        [Shadowing("_notes")]
        public string _notes { get; set; }

        public static Account_Accessor AttachShadow(object value);

        [Shadowing("Create@0")]
        public override void Create();
    }
}

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace NameHere.Bll
{
    [Shadowing("NameHere.Bll.ProjectBase`1")]
    public class ProjectBase_Accessor<T> : BaseShadow, INotifyPropertyChanged
    {
        protected static PrivateType m_privateType;

        public ProjectBase_Accessor(PrivateObject value);

        [Shadowing("Created")]
        public DateTime Created { get; set; }
        public static PrivateType ShadowedType { get; }

        [Shadowing("add_PropertyChanged@1")]
        public void add_PropertyChanged(PropertyChangedEventHandler value);
        public static ProjectBase_Accessor<T> AttachShadow(object value);

        [Shadowing("Create@0")]
        public virtual void Create();
    }
}

解决方案

The problem is that even though the accessor class exposes the same methods and properties as the class it shadows, there is no common interface between the accessor and the original class. Account_Accessor inherits from BaseShadow, Account inherits from something else. They are completely unrelated types as far as the compiler is concerned, not assignment compatible, so it will be difficult to pass instances of each into a common routine.

If you could force the Account_Accessor class to implement an interface type that is also implemented by the Account, then you can pass instances of each to functions that take the interface type as the parameter. Like this:

internal static IAccount SetupAccount(IAccount account, bool saveToDatabase)
{
// do account setup here - not construction
}

// to call: construct instance, then pass to common function
var account = new Account(a, b);
SetupAccount(account, true);

If construction of the Account instance is complex enough that you want to have a common routine for that too, put type-specific wrappers in front of the common function:

internal static IAccount CreateAccount(bool saveToDatabase)
{
    var account = new Account(a,b);
    return SetupAccount(account, saveToDatabase);
}

internal static IAccount CreateAccountAccessor(bool saveToDatabase)
{
    var account = new Account_Accessor(a,b);
    return SetupAccount(account, saveToDatabase);
}

One point you can't escape is this: somebody somewhere has to commit to which instance to construct. Even if you boil it down to passing types around and using Activator.CreateInstance(), somebody has to commit to selecting which type to use.

Once the instance is constructed, and both types implement a common interface, then all the common functions need to care about is the common interface.

这篇关于更新使用共享功能的两种常用功能的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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