报告代码执行和设计模式?

时间:2013-03-12 17:45:33

标签: c# unit-testing design-patterns logging report

首先,我要感谢大家对Stack Overflow社区的持续贡献!我多年来一直是Stack Overflow的成员,并且比任何其他在线资源更加依赖您的输入。虽然我尽可能地参与并回答成员的问题,但偶尔我会发现自己陷入困境并需要帮助。

说到我有一个不寻常的代码问题。我正在用C#编写一个API库,需要能够从WPF / Windows Forms应用程序调用,也可以从Unit Test代码中调用。

问题是我需要能够报告(在Excel中)在从WPF / Windows窗体应用程序中调用API时,是否正确执行库的每个方法,以及其他一些元数据和可选的返回类型。

当代码在单元测试中使用时,我并不真正关心报告,但我确实需要能够生成关于API调用是否正确执行的断言。

例如,如果在单元测试中我们有Test Initialize部分,则其中一个API调用可能是为要使用的测试方法创建域用户。另一个也可以创建一个域组,以便用户具有适当的组成员资格。

为了适应从WPF / WinForms中消耗API,我一直在重写API中的每个函数以返回OperationStep类型,希望当所有API调用都已执行时我将拥有{ {1}}我可以写入CSV文件。

所以问题是有没有更简单的方法来实现我迄今为止所做的工作?考虑到API库包含数百种类似的方法,报告编写非常繁琐且耗时。样品如下所述:

IEnumerable<OperationStep>

DomainContext是一个单例对象,其功能是连接到域控制器并创建用户,组,并将用户与组关联。

请注意,第二个和第三个方法调用都需要输出第一个,因此需要在OperationStep<PrincipalContext> createDomainConnectionStep = DomainContext.Current.GetPrincipalContext(settings.DomainInfo); OperationStep<UserPrincipal> createDomainUserStep = DomainContext.Current.CreateUser(createDomainConnectionStep.Context, settings.TestAccountInfo.Username, settings.TestAccountInfo.Password); OperationStep<GroupPrincipal> createDomainGroupStep = DomainContext.Current.CreateGroup(createDomainConnectionStep.Context, settings.TestAccountInfo.UserGrupName); 对象中包含public T Context,如下所述。

OperationResult对象由OperationStep接口继承的以下属性组成,但IOperation除外。

public T Context

方法调用本身有点臃肿乏味,但这是一个样本。

public class OperationStep<T> : IOperation
{
    /// <summary>
    /// Denotes the Logical Name of the current operation
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Denotes the stage of execution of the current operation: Setup, Execution, Validation, Cleanup 
    /// </summary>
    public OperationStage Stage { get; set; }

    /// <summary>
    /// Denotes whether the test step completed properly or failed.
    /// </summary>
    public OperationResult Result { get; set; }

    /// <summary>
    /// Denotes the return type of the test method.
    /// </summary>
    public T Context { get; set; }

    /// <summary>
    /// Denotes any other relevant information about the test step
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// If the test step result is failed, this should have the stack trace and the error message.
    /// </summary>
    public string Error { get; set; }
}

当理论上执行了所有方法调用时,我应该有一个public class DomainContext { private static volatile DomainContext currentContext; private static object synchronizationToken = new object(); /// <summary> /// default ctor. /// </summary> private DomainContext() { } /// <summary> /// Retrieves the Current DomainContext instance. /// </summary> public static DomainContext Current { get { if (currentContext == null) { lock (synchronizationToken) { if (currentContext == null) { currentContext = new DomainContext(); } } } return currentContext; } } /// <summary> /// Establishes a connection to the domain. /// </summary> /// <param name="domainInfo"></param> /// <returns></returns> public OperationStep<PrincipalContext> GetPrincipalContext(DomainInfo domainInfo) { OperationStep<PrincipalContext> result = new OperationStep<PrincipalContext>(); result.Name = "Establish Connection to Active Directory"; result.Result = OperationResult.Success; result.Stage = OperationStage.Setup; result.Description = string.Format("Domain Name: {0}, Default Containter: {1}", domainInfo.FQDN, domainInfo.Container); try { ContextType contextType = this.GetContextType(domainInfo.DomainType); PrincipalContext principalContext; try { principalContext = new PrincipalContext(contextType, domainInfo.FQDN, domainInfo.Container); } catch { throw new Exception("Unable to establish connection to Active Directory with the specified connection options."); } if (principalContext != null) { bool authenticationResult = principalContext.ValidateCredentials(domainInfo.Username, domainInfo.Password); if (!authenticationResult) { throw new Exception("Unable to authenticate domain admin user to Active Directory."); } result.Context = principalContext; result.Result = OperationResult.Success; } } catch(Exception ex) { result.Error = ex.Message; result.Result = OperationResult.Failure; } return result; } } ,在win格式的情况下,我可以写入csv文件(在MS Excel中查看)或单元测试我可以简单地省略额外的信息并忽略(除了连续执行的方法和IEnumerable<IOperation>属性)。

1 个答案:

答案 0 :(得分:1)

如果我理解正确的话 - 所有OperationStep s仅用于记录。那为什么不启用简单的.NET日志记录?记录所需的信息,方便您。您可以使用TraceSourceDelimetedTraceListener来写入.csv文件。比那更多的。您可以将日志记录逻辑移动到Strategy类,并在单元测试中覆盖其日志记录方法,这样就不会记录您调用Assert方法。