eXpressの永続オブジェクトとテスト

すべての人に良い一日を!

.NETの開発者向けにDevExpress™-eXpress Persistent Objects™(XPO)のORMを使用した場合に表示されるテスト機能についてお話します。



まず、特定のDBMSからの抽象化。

第二に、開発の初期段階およびテスト中に、DBMSはまったく必要ありません。





データベースの構造から始めましょう。

...

using DevExpress.Xpo;



namespace PrimerDlyaHabr {

public class Person : XPObject {

[Indexed( "LastName" , Unique = true )]

public string FirstName;

public string LastName;

public Decimal Wage;

[Association]

public Department Department;

public Person(Session session) : base (session) { }

}



public class Department : XPObject {

[Indexed(Unique = true )]

public string Name;

[Association]

public XPCollection<Person> Staff { get { return GetCollection<Person>( "Staff" ); } }

public Department(Session session) : base (session) { }

}

}




* This source code was highlighted with Source Code Highlighter .








部門(Department)とその中の従業員(Person)を表す2つのクラス(テーブル)があります。



それでは、それらのロジックをいくつか書いてみましょう。



...

using DevExpress.Xpo;

using DevExpress.Xpo.DB.Exceptions;

using DevExpress.Data.Filtering;

using DevExpress.Xpo.Metadata;



namespace PrimerDlyaHabr {

class PersonWork {

IDataLayer dataLayer;

// XPO

public PersonWork(IDataLayer dataLayer) {

this .dataLayer = dataLayer;

UpdateSchema();

}



// . .



void UpdateSchema(){

XPClassInfo[] classInfoList = new XPClassInfo[2];

classInfoList[0] = dataLayer.Dictionary.QueryClassInfo( typeof (Person));

classInfoList[1] = dataLayer.Dictionary.QueryClassInfo( typeof (Department));

dataLayer.UpdateSchema( false , classInfoList);

}



public void AddDepartment( string name) {

using (UnitOfWork session = new UnitOfWork(dataLayer)) {

Department dep = new Department(session);

dep.Name = name;

dep.Save();

session.CommitChanges();

}

}

public bool RemoveDepartment( string name){

using (UnitOfWork session = new UnitOfWork(dataLayer)){

Department dep = GetDepartment(session, name);

if (dep == null ) return false ;

session.Delete(dep.Staff);

session.Delete(dep);

session.CommitChanges();

return true ;

}

}



Department GetDepartment(UnitOfWork session, string name) {

return session.FindObject<Department>(CriteriaOperator.Parse( "Name = ?" , name));

}



public int AddPerson( string firstName, string lastName, Decimal wage, string departmentName) {

using (UnitOfWork session = new UnitOfWork(dataLayer)) {

Department dep = GetDepartment(session, departmentName);

if (dep == null ) throw new ArgumentException( string .Format( "Department '{0}' not found" , departmentName));

Person person = new Person(session);

person.FirstName = firstName;

person.LastName = lastName;

person.Wage = wage;

person.Department = dep;

person.Save();

session.CommitChanges();

return person.Oid;

}

}



public bool RemovePerson( int oid) {

using (UnitOfWork session = new UnitOfWork(dataLayer)) {

Person person = session.GetObjectByKey<Person>(oid);

if (person == null ) return false ;

session.Delete(person);

session.CommitChanges();

return true ;

}

}



CriteriaOperator GetSummaryCriteria( string departmentName) {

return string .IsNullOrEmpty(departmentName) ? null : CriteriaOperator.Parse( "Department.Name = ?" , departmentName);

}



public Decimal CalcWageSummary() {

return CalcDeparmentWageSummary( null );

}

public Decimal CalcDeparmentWageSummary( string name) {

using (UnitOfWork session = new UnitOfWork(dataLayer)) {

return (Decimal)session.Evaluate<Person>(CriteriaOperator.Parse( "Sum(Wage)" ), GetSummaryCriteria(name));

}

}



public int GetPersonCount() {

return GetDeparmentPersonCount( null );

}



public int GetDeparmentPersonCount( string name) {

using (UnitOfWork session = new UnitOfWork(dataLayer)) {

return ( int )session.Evaluate<Person>(CriteriaOperator.Parse( "Count()" ), GetSummaryCriteria(name));

}

}

}

}




* This source code was highlighted with Source Code Highlighter .








これで、オブジェクトからいくつかのアクションを実行するPersonWorkクラスができました(部門/人を追加/削除し、給与と従業員数を考慮します)。

コンストラクターで、クラスはIDataLayerインターフェイス(XPOのデータソースインターフェイス)を受け取ります。



このクラスをテストするには、NUnitフレームワークを使用します。



...

using System.Data;

using DevExpress.Xpo;

using DevExpress.Xpo.DB;

using NUnit.Framework;



namespace PrimerDlyaHabr {

[TestFixture]

public class PersonTests {

PersonWork personWork;



[SetUp]

public void SetUp() {

//

IDataStore dataStore = new InMemoryDataStore( new DataSet(), AutoCreateOption.DatabaseAndSchema);

//

IDataLayer dataLayer = new SimpleDataLayer(dataStore);

//

personWork = new PersonWork(dataLayer);

}



[Test]

public void Wage() {

personWork.AddDepartment( "Main" );

personWork.AddPerson( "Vasya" , "Pupkin" , 100, "Main" );

personWork.AddPerson( "Petya" , "Vasin" , 150, "Main" );



personWork.AddDepartment( "Additional" );

personWork.AddPerson( "Kostya" , "Kostin" , 90, "Additional" );

personWork.AddPerson( "Katya" , "Morozova" , 90, "Additional" );



Assert.AreEqual(100 + 150 + 90 + 90, personWork.CalcWageSummary());

Assert.AreEqual(100 + 150, personWork.CalcDeparmentWageSummary( "Main" ));

Assert.AreEqual(90 + 90, personWork.CalcDeparmentWageSummary( "Additional" ));

Assert.AreEqual(4, personWork.GetPersonCount());

Assert.AreEqual(2, personWork.GetDeparmentPersonCount( "Main" ));

Assert.AreEqual(2, personWork.GetDeparmentPersonCount( "Additional" ));

}

}

}




* This source code was highlighted with Source Code Highlighter .








出力は、1つのテストで1つのクラスのテストを受け取りました。 テストを実行するために、DBMSを使用可能にする必要はありません。

これらの目的のために、メモリ内のデータストアであり、腸でDataSetを使用するInMemoryDataStoreクラスがあります。

したがって、このDataSetを使用して、リポジトリからXMLに情報を保存できます。

このテストでは、2つの部門と4人の従業員を追加し、給与額と従業員数の計算方法を確認します。

テストは成功しました...システムの準備ができました...



次に、実際の条件で使用する必要があります。

これを行うには、フォームを追加し、コンストラクターでpersonWorkのインスタンスを作成します。



...

using DevExpress.Xpo.DB;

using DevExpress.Xpo;

...

PersonWork personWork;

public Form1() {

InitializeComponent();

// MSSql Server

string connectionString = MSSqlConnectionProvider.GetConnectionString( "Server" , "Database" );

// MSSql Server

IDataStore provider = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.DatabaseAndSchema);

//

IDataLayer dataLayer = new SimpleDataLayer(provider);

//

personWork = new PersonWork(dataLayer);

}

...




* This source code was highlighted with Source Code Highlighter .








//そして、目的のためにクラスを使用します...



つまり どのDBMSで動作するかを考えずに、既製のビジネスロジッククラスを取得しました...

終わり。






All Articles