如何自动化测试中等信任代码

13
我希望编写自动化测试,能够在中等信任级别下运行,并且如果需要完全信任就会失败。
我正在编写一个库,其中某些功能仅在完全信任的情况下才可用,并且我想验证我希望在中等信任级别下运行的代码是否可以正常工作。如果我更改需要完全信任的类,也想知道我的测试是否会失败。
我尝试创建另一个应用程序域并加载中等信任策略级别,但是在尝试运行跨应用程序域回调时,我总是会出现程序集或其依赖项无法加载的错误。
有没有办法解决这个问题?
更新:根据回复,这是我所拥有的内容。请注意,您要测试的类必须扩展MarshalByRefObject。这非常有限,但我看不到其他解决方法。
using System;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using Xunit;

namespace PartialTrustTest
{
    [Serializable]
    public class ClassUnderTest : MarshalByRefObject
    {
        public void PartialTrustSuccess()
        {
            Console.WriteLine( "partial trust success #1" );
        }

        public void PartialTrustFailure()
        {
            FieldInfo fi = typeof (Int32).GetField( "m_value", BindingFlags.Instance | BindingFlags.NonPublic );
            object value = fi.GetValue( 1 );
            Console.WriteLine( "value: {0}", value );
        }
    }

    public class Test
    {
        [Fact]
        public void MediumTrustWithExternalClass()
        {
            // ClassUnderTest must extend MarshalByRefObject
            var classUnderTest = MediumTrustContext.Create<ClassUnderTest>();

            classUnderTest.PartialTrustSuccess();
            Assert.Throws<FieldAccessException>( classUnderTest.PartialTrustFailure );
        }
    }

    internal static class MediumTrustContext
    {
        public static T Create<T>()
        {
            AppDomain appDomain = CreatePartialTrustDomain();
            var t = (T) appDomain.CreateInstanceAndUnwrap( typeof (T).Assembly.FullName, typeof (T).FullName );
            return t;
        }

        public static AppDomain CreatePartialTrustDomain()
        {
            var setup = new AppDomainSetup {ApplicationBase = AppDomain.CurrentDomain.BaseDirectory};
            var permissions = new PermissionSet( null );
            permissions.AddPermission( new SecurityPermission( SecurityPermissionFlag.Execution ) );
            permissions.AddPermission( new ReflectionPermission( ReflectionPermissionFlag.RestrictedMemberAccess ) );
            return AppDomain.CreateDomain( "Partial Trust AppDomain: " + DateTime.Now.Ticks, null, setup, permissions );
        }
    }
}
5个回答

7

这段内容是从《如何托管部分信任沙盒》中无耻地抄袭过来的,但为了好玩重新实现了一遍(并附带一个简单的测试案例)。

open System
open System.Reflection
open System.Security
open System.Security.Permissions
open System.Security.Policy

type Program() =
    inherit System.MarshalByRefObject()
    member x.PartialTrustSuccess() =
        Console.WriteLine("foo")
    member x.PartialTrustFailure() =
        let field = typeof<Int32>.GetField("m_value", BindingFlags.Instance ||| BindingFlags.NonPublic)
        let value = field.GetValue(1)
        Console.WriteLine("value: {0}", value)

[<EntryPoint>]
let main _ =
    let appDomain =
        let setup = AppDomainSetup(ApplicationBase = AppDomain.CurrentDomain.BaseDirectory)
        let permissions = PermissionSet(null)
        permissions.AddPermission(SecurityPermission(SecurityPermissionFlag.Execution)) |> ignore
        permissions.AddPermission(ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)) |> ignore
        AppDomain.CreateDomain("Partial Trust AppDomain", null, setup, permissions)

    let program = appDomain.CreateInstanceAndUnwrap(
                      typeof<Program>.Assembly.FullName,
                      typeof<Program>.FullName) :?> Program

    program.PartialTrustSuccess()

    try
        program.PartialTrustFailure()
        Console.Error.WriteLine("partial trust test failed")
    with
        | :? FieldAccessException -> ()

    0

还有一个C#版本:

using System;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;

namespace PartialTrustTest
{
    internal class Program : MarshalByRefObject
    {
        public void PartialTrustSuccess()
        {
            Console.WriteLine("partial trust success #1");
        }

        public void PartialTrustFailure()
        {
            FieldInfo fi = typeof(Int32).GetField("m_value", BindingFlags.Instance | BindingFlags.NonPublic);
            object value = fi.GetValue(1);
            Console.WriteLine("value: {0}", value);
        }

        private static AppDomain CreatePartialTrustDomain()
        {
            AppDomainSetup setup = new AppDomainSetup() { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory };
            PermissionSet permissions = new PermissionSet(null);
            permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
            permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
            return AppDomain.CreateDomain("Partial Trust AppDomain", null, setup, permissions);
        }

        static void Main(string[] args)
        {
            AppDomain appDomain = CreatePartialTrustDomain();

            Program program = (Program)appDomain.CreateInstanceAndUnwrap(
                typeof(Program).Assembly.FullName,
                typeof(Program).FullName);

            program.PartialTrustSuccess();

            try
            {
                program.PartialTrustFailure();
                Console.Error.WriteLine("!!! partial trust test failed");
            }
            catch (FieldAccessException)
            {
                Console.WriteLine("partial trust success #2");
            }
        }
    }
}
C:\temp\PartialTrustTest\bin\Debug>PartialTrustTest.exe
部分信任成功 #1
部分信任成功 #2
在这段代码中,程序被执行并显示了两个“部分信任成功”的消息。

尝试了一段时间,无法基于您的代码或源材料获得可工作的单元测试。您是否成功将其放入C#单元测试中,并适当地使测试通过和失败? - Ian Davis

2

我刚刚发布了一篇文章,标题为使用xUnit.net进行部分信任测试。它详细介绍了在Entity Framework团队中使用的基于xUnit.net的框架,用于在部分信任下执行代码。

以下是其使用示例。

public class SomeTests : MarshalByRefObject
{
    [PartialTrustFact]
    public void Partial_trust_test1()
    {
        // Runs in medium trust
    }
}

// Or...

[PartialTrustFixture]
public class MoreTests : MarshalByRefObject
{
    [Fact]
    public void Another_partial_trust_test()
    {
        // Runs in medium trust
    }
}

问题在于你的代码不再适用于最新版本的xUnit......它们在1.9和2.0之间甚至在2.0和2.1之间对API进行了太大的改变...... - shytikov

1

我也应该指出,在这篇文章中有一个可下载的基类,您可以在任何NUnit fixture中使用。 - Alex Norcliffe
那个链接似乎已经失效了 - 你有这些文章的新地址吗? - Robert Foster

0
答案取决于你的代码在有中等信任权限的用户尝试访问完全信任的功能时会发生什么。我想会抛出一些异常。
在这种情况下,请编写一个单元测试,该测试在中等信任上下文中运行,尝试访问完全信任的功能,并期望抛出异常。如果您从未编写过此类测试,则大多数测试框架都支持以下常见方法:
testMediumTrustUserWontAccessFeatureX()
{
    // set up the context of your test ...

    try
    {
        accessFullTrustFeature();
        fail("Test failed - Medium trust user can access full trust feature");
    }
    catch( SomeKindOfException e )
    {
        // Success - feature was denied to the untrusted user 
    }
}

如果捕获了异常,意味着您的不可信用户未能访问该功能(测试通过),但如果从未捕获异常,则测试失败(我们预期会出现异常,但没有出现)。
这是类似Java伪代码的模式,但只要使用了异常处理,就应该可以在任何语言中使用。

是的,我预计在运行需要完全信任的代码时会抛出异常。我还没有能够实现测试中“//设置测试上下文…”部分以建立中等信任上下文来运行代码。我编写了一个库,希望验证其所有例程都可以在中等信任环境中成功运行。 - Ian Davis

0

我从未尝试过这样做,但是一般来说,要处理自定义 AppDomain 中的程序集加载失败,您可以使用 AppDomain.AssemblyResolve 事件。

虽然毫不相关,但这里有一个 使用 AppDomain.AssemblyResolve 的示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接