Как автоматизировать тестирование среднего целевого кода

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

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

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

Ответы

Ответ 1

Я только что опубликовал статью под названием Partial Trust Testing с помощью 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
    }
}

Ответ 2

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

Ответ 3

Я разместил сообщение в блоге с тремя частями по модульному тестированию в Media Trust

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

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

Ответ 4

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

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

Ответ 5

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

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

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