2015-06-26 15 views
6

Trong C#/nHibernate-projects Tôi đang sử dụng SQLite để kiểm tra đơn vị mã của tôi, aproximately sử dụng phương pháp được mô tả ở đây: http://ayende.com/blog/3983/nhibernate-unit-testing.Sao chép cơ sở dữ liệu SQLite trong bộ nhớ để thực hiện kiểm tra đơn vị nhanh hơn

Tuy nhiên, tôi thấy rằng việc xây dựng và định cấu hình cơ sở dữ liệu trong bộ nhớ thường mất khoảng 150 mili giây. Tôi có rất nhiều bài kiểm tra đơn vị để điều này nhanh chóng tăng lên.

Tôi muốn xây dựng và cấu hình cơ sở dữ liệu một lần, lưu trữ nó trong một biến tĩnh và sao chép nó mỗi lần kiểm tra đơn vị cần một cơ sở dữ liệu.

Làm cách nào để sao lưu cơ sở dữ liệu trong bộ nhớ?

Lần đầu tiên tôi cố gắng tạo cơ sở dữ liệu trong bộ nhớ có tên. Theo số https://www.sqlite.org/inmemorydb.html điều này là có thể. Tôi đã từng có:

private const string ConnectionString = "Data Source=:memory:;Version=3;"; 

chuỗi kết nối tôi đã cố gắng là:

private const string ConnectionString = "FullUri=file:memorydb.db?mode=memory&cache=shared"; 
    private const string ConnectionString2 = "FullUri=file:memorydb2.db?mode=memory&cache=shared"; 

Vì vậy, bây giờ tôi chỉ cần có để tìm hiểu làm thế nào để nhanh chóng sao chép nội dung từ một đến khác? Tôi gần như ở đó: Tôi có thể tạo hai cơ sở dữ liệu trong bộ nhớ và gọi "BackupDatabase" để sao chép cơ sở dữ liệu.

Các đơn vị kiểm tra tuy nhiên, hoạt động như các "dụ" cơ sở dữ liệu không có bảng biểu, ngay cả những "nguyên mẫu" cơ sở dữ liệu không.

 private static ISessionFactory _prototypeSessionFactory; 
     private const string InstanceConnectionString = "FullUri=file:memorydb.db?mode=memory&cache=shared"; 

     private const string PrototypeConnectionString = "FullUri=file:memorydb2.db?mode=memory&cache=shared"; 
     private SQLiteConnection _instanceConnection; 
     private ISessionFactory _instanceSessionFactory; 

     public DatabaseScope(Assembly assembly) 
     { 
      var prototyeConfiguration = SQLiteConfiguration.Standard.ConnectionString(PrototypeConnectionString); 
      var cfg = Fluently 
       .Configure() 
       .Database(prototyeConfiguration) 
       .Mappings(m => m.HbmMappings.AddFromAssembly(assembly)); 
      cfg.ExposeConfiguration(BuildSchema); 
      _prototypeSessionFactory = cfg.BuildSessionFactory(); 

      var instanceConfiguration = SQLiteConfiguration.Standard.ConnectionString(InstanceConnectionString); 
      _instanceSessionFactory = Fluently 
       .Configure() 
       .Database(instanceConfiguration) 
       .BuildSessionFactory(); 

      CopyDatabase(); 
     } 

     private void CopyDatabase() 
     { 
      var cnnIn = new SQLiteConnection(PrototypeConnectionString); 
      var cnnOut = new SQLiteConnection(InstanceConnectionString); 
      cnnIn.Open(); 
      cnnOut.Open(); 
      cnnIn.BackupDatabase(cnnOut, "main", "main", -1, null, -1); 
      cnnIn.Close(); 
      cnnOut.Close(); 
     } 
+0

theo [bài viết này] (https://www.sqlite.org/backup.html) (nhìn vào loadOrSaveDb chẳng hạn). Có vẻ như bạn cần sử dụng 'sqlite3_backup_init()' với một con trỏ tới DB đích. Tuy nhiên tôi không nghĩ rằng nó sẽ giải quyết vấn đề của bạn. các bài kiểm tra của bạn giống như một bài kiểm tra tích hợp không phải là UT. Tôi nghĩ bạn nên cân nhắc sử dụng khung mocking và thay thế DB của bạn. –

+0

Cảm ơn bạn đã phản hồi, Old Fox. Bạn nói đúng: họ là thử nghiệm tích hợp một phần. Và chúng hoạt động hoàn hảo, chỉ chậm một chút, gây đau cho hơn 300 bài kiểm tra. Tôi không mong được viết lại nhiều bài kiểm tra đó, nhưng vì lợi ích của đối số: bạn sẽ thay thế cơ sở dữ liệu bằng cách sử dụng một khuôn khổ mocking như thế nào? (Tôi xem xét những gì tôi đang làm mocking: Tôi đang sử dụng SQLite để giả lập cơ sở dữ liệu của tôi, đảm bảo rằng mọi thứ hoạt động als miễn là ánh xạ nHibernate của tôi là chính xác.) – realbart

+0

Tôi nghĩ rằng hơn 300 bài kiểm tra tích hợp xác minh ánh xạ là một chút quá nhiều ... Tôi tin rằng mã của bạn hoạt động trực tiếp với 'NHibernate'. Nếu vậy, tôi khuyên bạn nên chia các bài kiểm tra thành 2 loại: 1. hành vi + gọi OEM chính xác (giả OEM. Có lẽ hầu hết các bài kiểm tra tồn tại của bạn). 2. Kiểm tra tích hợp - OEM ánh xạ đúng loại (có thể 10% từ 300 thử nghiệm trở lên). Về việc giả mạo DB, hãy quên nó đi, đó là lỗi của tôi .... –

Trả lời

2

tôi đã kết thúc với mã làm việc này. Thời gian thử nghiệm đơn vị của tôi đã kéo dài từ trên mười phút đến dưới hai phút. (Mã số hơi đơn giản hóa cho dễ đọc)

using System; 
using System.Data; 
using System.Data.SQLite; 
using System.IO; 
using System.Reflection; 
using FluentNHibernate.Cfg; 
using FluentNHibernate.Cfg.Db; 
using NHibernate; 
using NHibernate.Mapping; 
using NHibernate.Tool.hbm2ddl; 

namespace TestHelper.DbHelper.SqLite 
{ 
    public class DatabaseScope : IDisposable 
    { 
     private static Assembly _prototypeAssembly; 
     private const string PrototypeConnectionString = "FullUri=file:prototype.db?mode=memory&cache=shared"; 
     private static ISessionFactory _prototypeSessionFactory; 
     private static SQLiteConnection _prototypeConnection; 

     private const string InstanceConnectionString = "FullUri=file:instance.db?mode=memory&cache=shared"; 
     private ISessionFactory _instanceSessionFactory; 
     private SQLiteConnection _instanceConnection; 

     public DatabaseScope(Assembly assembly) 
     { 
      InitDatabasePrototype(assembly); 
      InitDatabaseInstance(); 
     } 

     private void InitDatabasePrototype(Assembly assembly) 
     { 
      if (_prototypeAssembly == assembly) return; 

      if (_prototypeConnection != null) 
      { 
       _prototypeConnection.Close(); 
       _prototypeConnection.Dispose(); 
       _prototypeSessionFactory.Dispose(); 
      } 

      _prototypeAssembly = assembly; 

      _prototypeConnection = new SQLiteConnection(PrototypeConnectionString); 
      _prototypeConnection.Open(); 

      _prototypeSessionFactory = Fluently 
       .Configure() 
       .Database(SQLiteConfiguration.Standard.ConnectionString(PrototypeConnectionString)) 
       .Mappings(m => m.HbmMappings.AddFromAssembly(assembly)) 
       .ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(false, true, false, _prototypeConnection, null)) 
       .BuildSessionFactory(); 
     } 

     private void InitDatabaseInstance() 
     { 
      _instanceSessionFactory = Fluently 
       .Configure() 
       .Database(SQLiteConfiguration.Standard.ConnectionString(InstanceConnectionString)) 
       .Mappings(m => m.HbmMappings.AddFromAssembly(_prototypeAssembly)) 
       .BuildSessionFactory(); 

      _instanceConnection = new SQLiteConnection(InstanceConnectionString); 
      _instanceConnection.Open(); 

      _prototypeConnection.BackupDatabase(_instanceConnection, "main", "main", -1, null, -1); 
     } 

     public ISession OpenSession() 
     { 
      return _instanceSessionFactory.OpenSession(_instanceConnection); 
     } 

     public void Dispose() 
     { 
      _instanceConnection.Close(); 
      _instanceConnection.Dispose(); 
      _instanceSessionFactory.Dispose(); 
     } 
    } 
} 
1

Điều tôi đã quan sát với SQLite trong cơ sở dữ liệu bộ nhớ là ngay khi bạn đóng kết nối, mọi thứ trong db đều biến mất. Vì vậy, để làm những gì bạn muốn,

  1. Tạo nhà máy phiên cho cơ sở dữ liệu sao lưu, phiên mở và xây dựng giản đồ không đóng phiên này cho đến khi bạn hoàn thành toàn bộ bộ kiểm tra của bạn

  2. Tạo nhà máy phiên cho bạn nhắm mục tiêu cơ sở dữ liệu, phiên mở và sử dụng kết nối từ đối tượng session này và kết nối từ phiên được tạo ra từ bước 1 để sao chép dữ liệu

  3. sử dụng phiên tạo ra trên bước 2 để kiểm tra và đóng nó lại một lần kiểm tra xong

Một giải pháp khác là sử dụng phiên duy nhất để thực hiện nhiều xét nghiệm (tất cả các bài kiểm tra trong trận đấu thử nghiệm duy nhất) thì bạn không cần phải tạo ra nhà máy phiên mới mỗi thử nghiệm, nhưng mỗi TestFixture

+0

Không xây dựng giản đồ phần tốn nhiều thời gian nhất để tạo cơ sở dữ liệu sqlite từ nhibernate-mappings? Đó là bước tôi đang cố gắng để circomvent ... Không có "cắt ngắn tất cả các bảng" -command, là có? – realbart

+0

Tôi không chắc chắn tạo lược đồ là nút cổ chai hay, tạo và thiết lập kết nối. Một lựa chọn cho việc này là tạo ra trong bộ nhớ db một lần và tái sử dụng cùng một phiên cho nhiều thử nghiệm với việc tạo giao dịch tại mỗi lần kiểm tra bắt đầu và quay trở lại vào cuối của thử nghiệm. –

+0

Jip. Tôi đã nhận nó làm việc folliwing hướng dẫn của bạn. Tôi tham chiếu db sai ở một nơi khác trong mã. – realbart

Các vấn đề liên quan