Вопрос

Я хотел бы написать автоматизированные тесты, которые выполняются со средним уровнем доверия и терпят неудачу, если для них требуется полное доверие.

Я пишу библиотеку, в которой некоторые функции доступны только в сценариях полного доверия, и хочу убедиться, что код, который я хочу запустить при среднем доверии, будет работать нормально.Если я также хочу знать, что если я изменю класс, требующий полного доверия, мои тесты не пройдут.

Я попытался создать другой AppDomain и загрузить PolicyLevel со средним уровнем доверия, но всегда получаю сообщение об ошибке сборки или его зависимость не может быть загружена при попытке запустить перекрестный обратный вызов AppDomain.

Есть ли способ осуществить это?

ОБНОВЛЯТЬ:Судя по ответам, вот что у меня есть.Обратите внимание, что тестируемый класс должен расширять 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 );
        }
    }
}
Это было полезно?

Решение

Я только что опубликовал статью под названием Частичное доверительное тестирование с помощью xUnit.net.В нем подробно описана платформа на основе xUnit.net, которую мы используем в команде Entity Framework для проверки кода с частичным доверием.

Вот пример его использования.

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

Другие советы

Бессовестно украдено у Как разместить песочницу с частичным доверием — №7, но переопределен (вместе с простым тестовым примером) на F# просто для прикола :-)

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

И версия С#:

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
 partial trust success #1
 partial trust success #2

Я опубликовал сообщение в блоге из трех частей о модульном тестировании в Medium Trust.

Я создаю альтернативный домен приложения аналогично некоторым ответам здесь, но пойду дальше, используя MarshalByRefObject для вызова тестового метода в другом домене приложения, что означает, что вашим тестовым классам не нужно реализовывать MarshalByRefObject.

Третья часть (содержащая ссылки на остальные части) находится здесь. http://boxbinary.com/2011/10/how-to-run-a-unit-test-in-medium-trust-with-nunitpart-three-umbraco-framework-testing/

Я никогда не пытался это сделать, но в целом для обработки ошибок загрузки сборки из пользовательских доменов приложений можно использовать событие AppDomain.AssemblyResolve.

Хотя это совершенно не связано, вот пример использования AppDomain.AssemblyResolve.

Ответ зависит от того, что делает ваш код, когда кто-то со средним уровнем доверия пытается получить доступ к функции полного доверия.Я предполагаю, что будет выбрано какое-то исключение.

В этом случае напишите модульный тест, который выполняется в контексте среднего доверия, пытается получить доступ к функции полного доверия и ожидает создания исключения.Если вы никогда не писали подобные тесты, один из распространенных способов сделать это, который поддерживает большинство платформ тестирования, заключается в следующем:

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, но этот шаблон должен работать на любом языке, который вы используете, при условии, что он поддерживает обработку исключений.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top