Как автоматизировать тестирование кода среднего доверия - PullRequest
13 голосов
/ 12 июня 2009

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

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

Я попытался создать еще один 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 );
        }
    }
}

Ответы [ 5 ]

7 голосов
/ 19 ноября 2009

Бесстыдно украдено у Как разместить изолированную программную среду с частичным доверием - # 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

И версия на 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
 partial trust success #1
 partial trust success #2
2 голосов
/ 30 августа 2012

Я только что опубликовал статью под названием Частичное доверительное тестирование с 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
    }
}
1 голос
/ 21 октября 2011

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

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

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

0 голосов
/ 22 октября 2009

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

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

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

0 голосов
/ 12 августа 2009

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

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

...