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