3

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

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

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

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

例如,如果在单元测试中我们有Test Initialize一部分,API 调用之一可能是创建一个域用户供测试方法使用。另一个人也可以创建一个域组,以便用户拥有适当的组成员身份。

为了适应 WPF/WinForms 对 API 的使用,我一直在重写 API 中的每个函数以返回一个OperationStep类型,希望在所有 API 调用都执行IEnumerable<OperationStep>后,我可以将其写入 CSV 文件。

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

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);

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

请注意,第二个和第三个方法调用都需要第一个的输出,因此保证需要public T ContextOperationResult对象内具有如下所述的。

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;
    }
}

当所有方法调用都已执行理论上,我应该有一个IEnumerable<IOperation>在 win 表单的情况下我可以写入 csv 文件(在 MS Excel 中查看)或在单元测试的情况下我可以简单地省略额外信息和忽略(除了连续执行的方法和T Context属性)。

4

1 回答 1

1

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

于 2013-03-27T06:53:50.733 回答