中程度の信頼コードのテストを自動化する方法
-
13-09-2019 - |
質問
中程度の信頼で実行され、完全な信頼が必要な場合は失敗する自動テストを作成したいと考えています。
一部の機能が完全な信頼のシナリオでのみ利用できるライブラリを作成していますが、中程度の信頼で実行したいコードが正常に動作することを確認したいと考えています。完全な信頼を必要とするクラスを変更すると、テストが失敗することも知りたい場合。
別の 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 を使用した部分信頼テスト. 。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
}
}
他のヒント
恥知らずにも盗まれました 部分信頼サンドボックスをホストする方法 – #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
Medium Trust での単体テストに関する 3 部構成のブログ投稿を投稿しました。
ここでのいくつかの回答と同様の方法で代替 AppDomain をスピンアップしますが、MarshalByRefObject を使用して他の AppDomain のテスト メソッドを呼び出すことでさらに進めます。つまり、テスト クラスは MarshalByRefObject を実装する必要がありません。
パート 3 (他のパートへのリンクを含む) はここにあります http://boxbinary.com/2011/10/how-to-run-a-unit-test-in-medium-trust-with-nunitpart-three-umbraco-framework-testing/
私はこれを試みたことはありませんが、一般に、カスタム AppDomain からのアセンブリ読み込みの失敗を処理するには、AppDomain.AssemblyResolve イベントを使用できます。
全く関係ありませんが、こちら AppDomain.AssemblyResolve の使用例.
答えは、中程度の信頼特権を持つユーザーが完全な信頼機能にアクセスしようとしたときにコードが何を行うかによって異なります。何らかの例外がスローされると思います。
その場合は、中程度の信頼コンテキストで実行され、完全な信頼機能へのアクセスを試み、例外がスローされることを予期する単体テストを作成します。このようなテストを書いたことがない場合は、ほとんどのテスト フレームワークでサポートされている一般的な方法の 1 つを次に示します。
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 風の疑似コードですが、例外処理がサポートされていると仮定すると、このパターンは使用している言語を問わず機能するはずです。