2

Instanciateメソッドをオーバーライドし、次のことを行う NHibernate インターセプターがあります。

  • インスタンス化されるクラスが特定の基本クラスを継承する場合、CastleDynamicProxy を返します
  • それ以外の場合は、クラスをインスタンス化するだけです

これはかなり簡単に聞こえますが (そして既に機能しています)、単体テストでその機能を証明できれば、さらに気分が良くなります。

インターセプターのコードは次のとおりです。

    public override object Instantiate(string entityTypeName, EntityMode entityMode, object id)
    {
        // Type resolution across Assembly borders
        Type type = TypeFinder.FindType(entityTypeName);

        if (type == null)
        {
            throw new Exception(string.Format("",entityTypeName));
        }

        bool isViewModel = (typeof(ViewModelBase).IsAssignableFrom(type));

        if (entityMode == EntityMode.Poco && isViewModel)
        {
            var instance = ProxyFactory.CreateProxy(type);
            SessionFactory.GetClassMetadata(entityTypeName).SetIdentifier(instance, id, entityMode);
            return instance;
        }
        return base.Instantiate(entityTypeName, entityMode, id);
    }

プロキシ生成コードを正常にテストできますが、base.Instantiate常に null が返されます。これが私のテスト コードです (ご覧のとおり、Interceptor が有効なセッションを必要とする場合に備えて、実際のデータベースも追加しました)。

    private FluentConfiguration PrepareDataBase()
    {
        string connectionString = @"Data Source=test.sdf;";
        SqlCeEngine en = new SqlCeEngine(connectionString);
        en.CreateDatabase();

        FluentConfiguration fc = Fluently.Configure().Database(MsSqlCeConfiguration.Standard
                                                              .ConnectionString(c => c.Is(connectionString))
                                                              .ShowSql())
                                   .Mappings(x => x.FluentMappings.AddFromAssemblyOf<ViewModel>());

        new SchemaExport(fc.BuildConfiguration()).Create(true, true);
        return fc;
    }

    [TestMethod]  
    [DeploymentItem("System.Data.SqlServerCe.dll")]
    public void Test_Instantiate_WithNonViewModelBasedPoco_ReturnsInstance()
    {
        TypeFinder.RegisterAssembly(typeof(OtherPoco).Assembly);
        FluentConfiguration fc = PrepareDataBase();

        NhChangeNotificationInterceptor interceptor = new NhChangeNotificationInterceptor(); 
        ISession session = fc.BuildSessionFactory().OpenSession(interceptor);

        string instanceType = typeof(OtherPoco).FullName;
        object instance = interceptor.Instantiate(instanceType, EntityMode.Poco, null);

        Assert.AreEqual(typeof(OtherPoco).FullName, instance.GetType().FullName);
        Assert.IsFalse(typeof(ViewModelBase).IsAssignableFrom(instance.GetType()));
    }

null 識別子に問題があるのではないかと考えたので、レコードを保存し、その Id を次のように追加しようとしました。

        NhChangeNotificationInterceptor interceptor = new NhChangeNotificationInterceptor(); 
        ISession session = fc.BuildSessionFactory().OpenSession(interceptor);
        using (ITransaction trx = session.BeginTransaction())
        {
            session.Save(new OtherPoco() { Id = 1 });
            session.Flush();
        }
        string instanceType = typeof(OtherPoco).FullName;
        object instance = interceptor.Instantiate(instanceType, EntityMode.Poco, 1);

といっても、何も変わりません。どのようにテストできますbase.Instantiateか?

4

1 に答える 1

2

このための単体テストを作成しようとはしません。インターセプターは NH/データベースと密接に結合されています。これについては統合テストを作成することをお勧めします。

コード行をテストしようとしないでください。代わりに、機能をテストしてください。インターセプターが何をすべきかをすでに述べました(「インスタンス化されるクラスが特定の基本クラスを継承する場合は、CastleDynamicProxy を返します。それ以外の場合は、単にクラスをインスタンス化します」)。代わりにこれをテストしてください!後でインターセプター以外の手法を使用して同じ結果を得たい場合は、テストを変更する必要はありません。

したがって、interceptor.Instantiate をテストから直接呼び出す代わりに、db からデータを取得するときに本来の動作を行うことを確認する統合テストをいくつか作成してください。

于 2013-02-25T14:55:58.667 に答える