2010-03-01 23 views
6

Tôi đang cố gắng tạo kho lưu trữ giả để kiểm tra đơn vị với đối tượng lớp có quan hệ một đến nhiều. Tôi đang sử dụng ASP.NET MVC và LINQ to SQL. Tài liệu tham khảo của tôi là cuốn sách "Pro ASP.NET MVC Framework" của Steven Sanderson.Cách tạo kho lưu trữ giả với liên kết 1 đến nhiều cho MVC

tôi đã tạo ra các lớp học với các hiệp hội Entity:

[Table(Name = "Albums")] 
public class Album 
{ 
    [Column(IsDbGenerated = true, IsPrimaryKey = true)] 
    public int AlbumID { get; set; } 
    [Column] 
    public string Title { get; set; } 

    private EntitySet<Track> _tracks; 

    [Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
    public EntitySet<Track> Tracks 
    { 
     get { return _tracks; } 
     set { _tracks.Assign(value); } 
    } 
} 

[Table(Name = "Tracks")] 
public class Track 
{ 
    [Column(IsPrimaryKey = true)] 
    public int TrackID { get; set; } 
    [Column] 
    public string Title { get; set; } 
    [Column] 
    public int AlbumID { get; set; } 
} 

Và một giao diện trừu tượng cho kho:

public interface IMusicRepository 
{ 
    IQueryable<Album> Albums { get; } 
    IQueryable<Track> Tracks { get; } 
} 

tôi đã có thể tạo ra một kho lưu trữ giả cho Album - FakeMusicRepository:

public class FakeMusicRepository : IMusicRepository 
{ 

    private static IEnumerable<Track> fakeTracks = new List<Track> 
    { 
     new Track {AlbumID = 1, TrackID = 1, Title = "Flood"}, 
     new Track {AlbumID = 1, TrackID = 2, Title = "Liquid"}, 
     new Track {AlbumID = 2, TrackID = 1, Title = "Song 1"}, 
     new Track {AlbumID = 2, TrackID = 2, Title = "Song 2"} 
    }.AsEnumerable(); 

    private static IQueryable<Album> fakeAlbums = new List<Album> 
    { 
      new Album {AlbumID = 1, Title = "Jars of Clay"}, 
      new Album {AlbumID = 2, Title = "Wind in the Wheat"} 
    }.AsQueryable(); 


    public IQueryable<Album> Albums 
    { 
     get { return fakeAlbums; } 
    } 

    public IQueryable<Track> Tracks 
    { 
     get { return fakeTracks.AsQueryable(); } 
    } 

} 

Chỉ hoạt động tốt miễn là tôi không cố gắng truy cập bất kỳ tuyến đường nào. Nói cách khác, Album.Title hoạt động nhưng truy cập vào Album.Tracks.Count() sẽ tạo ra một ngoại lệ tham chiếu null. Tôi đã không chắc chắn nếu Linq-To-SQL hoặc LINQ-To-Objects sẽ đón Hiệp hội và sử dụng nó tự động với các đối tượng giả hay không.

Vấn đề là dù tôi cố gắng làm gì và dường như không thể chỉ định lớp Tracks cho Album. Tôi biết rằng EntitySet được dựa trên IEnumerable nhưng nó là một thách thức để đúc danh sách Enumerable vào một EntitySet.

Album được mong đợi một EntitySet nhưng cách duy nhất tôi đã có thể vượt qua trong đó là thông qua một helper tùy chỉnh:

public static class EntityCollectionHelper 
{ 
    public static EntitySet<T> ToEntitySet<T>(this IEnumerable<T> source) where T : class 
    { 
     EntitySet<T> set = new EntitySet<T>(); 
     set.AddRange(source); 
     return set; 
    } 
} 

Đây là càng gần như tôi đã đến:

public class FakeMusicRepository2 : IMusicRepository 
{ 
    private static IEnumerable<Track> fakeTracks = new List<Track> 
    { 
     new Track {AlbumID = 1, TrackID = 1, Title = "Flood"}, 
     new Track {AlbumID = 1, TrackID = 2, Title = "Liquid"}, 
     new Track {AlbumID = 2, TrackID = 1, Title = "Song 1"}, 
     new Track {AlbumID = 2, TrackID = 2, Title = "Song 2"} 
    }.AsEnumerable(); 

    private static EntitySet<Track> Tracks1 = (from t in fakeTracks where t.AlbumID == 1 select t).ToEntitySet(); 
    private static EntitySet<Track> Tracks2 = (from t in fakeTracks where t.AlbumID == 2 select t).ToEntitySet(); 

    private static IQueryable<Album> fakeAlbums = new List<Album> 
    { 
      new Album {AlbumID = 1, Title = "Jars of Clay", Tracks=Tracks1}, 
      new Album {AlbumID = 2, Title = "Wind in the Wheat", Tracks=Tracks2} 
    }.AsQueryable(); 


    public IQueryable<Album> Albums 
    { 
     get { return fakeAlbums; } 
    } 

    public IQueryable<Track> Tracks 
    { 
     get { return fakeTracks.AsQueryable(); } 
    } 

} 

Tuy nhiên, khi tôi cố gắng truy cập Album.Tracks tôi nhận được

System.NullReferenceException: Tham chiếu đối tượng không được đặt thành phiên bản của o bject.

Đây là thử nghiệm implamentation/đơn vị:

[Test] 
    public void Test_FakeMusicRepository() 
    { 
     // Arrange: Setup Repository 
     var dc = new FakeMusicRepository2(); 

     // Act: 
     var albums = dc.Albums.AsQueryable(); 
     // Load the first test location 
     Album album = dc.Albums.First(); 

     // Assert: That there are records in the Album Object 
     Assert.Greater(albums.Count(), 0, "No Albums Records Returned!"); 

     //Assert that our first Album is not Null 
     Assert.IsNotNull(album, "returned Album is Null!"); 
     // Assert: That we have the correct Album 
     Assert.AreEqual(album.AlbumID, 1, "Returned Album ID is not correct!"); 

     // Try to Count the related sub table (Tracks) 
     var trackCount = album.Tracks.Count(); 

     // Try to get the first Track 
     var track1 = album.Tracks.FirstOrDefault(); 


     // Assert: The Album has Tracks 
     Assert.Greater(trackCount, 0, "Album has no Tracks"); 

     // Assert: That First track is not Null 
     Assert.IsNotNull(track1, "Track1 object was Null!"); 

     // Assert: That Track1 has data 
     Assert.IsNotNull(track1.TrackID, "Track1's ID was Null!"); 
    } 

Tôi đã trải qua những ngày tìm kiếm một câu trả lời cho câu hỏi này và đã không tìm thấy bất kỳ ví dụ vì vậy nếu một người nào đó sẽ có thể gửi một lao động ví dụ trả lời Tôi chắc rằng những người khác cũng sẽ thích.

Tôi rất mới với MVC và kiểm tra đơn vị vì vậy hãy dễ dàng với tôi. Tôi có IoC và Moq trên tay là tốt nhưng tôi biết thậm chí ít hơn về những điều này nhưng tôi đang lập kế hoạch sử dụng cả hai với dự án này. Nếu có một cách tốt hơn để làm điều này thì tôi là tất cả tai! Cảm ơn.

+0

Bạn có mã mà bạn đang sử dụng để truy cập tuyến đường không? I E. mã triển khai của bạn? Điều đó có thể giúp gỡ lỗi. Nếu bạn đang làm Album.Tracks.Count() thì lý do có thể là bạn không chỉ định đúng bài hát, nhưng nó phụ thuộc vào mã thực hiện. – Odd

+0

Ý tưởng hay - Tôi đã đăng mã thử nghiệm/triển khai đơn vị của mình. – ColinICN

Trả lời

2

Lớp Album có vẻ hơi kỳ lạ và đặc biệt là phần này:

private EntitySet<Track> _tracks; 

[Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
public EntitySet<Track> Tracks 
{ 
    get { return _tracks; } 
    set { _tracks.Assign(value); } 
} 

Các thành viên tin _tracksbao giờ gán một giá trị và bạn gọi phương thức Assign vào nó trong setter mà ném ngoại lệ. Bằng cách này, trình biên dịch nên cảnh báo bạn.Bạn có thể thử cung cấp một giá trị mặc định hoặc kiểm tra null trong setter trước khi gọi phương thức Assign:

private EntitySet<Track> _tracks = new EntitySet<Track>(); 

Ngoài ra phương pháp mở rộng của bạn để chuyển đổi một IEnumerable<T>-EntitySet<T> có vẻ tốt đẹp.

Và cuối cùng khi bạn gán các album giả bạn cần phải thiết lập các bài hát:

private static IQueryable<Album> fakeAlbums = new List<Album> 
{ 
     new Album 
     { 
      AlbumID = 1, 
      Title = "Jars of Clay", 
      Tracks = fakeTracks.ToEntitySet() 
     }, 
     new Album 
     { 
      AlbumID = 2, 
      Title = "Wind in the Wheat", 
      Tracks = fakeTracks.ToEntitySet() 
     } 
}.AsQueryable(); 
+0

Cảm ơn Darivn - thêm _tracks = new EntitySet (); giải quyết nó. Như bạn đã nói, tôi không chỉ định giá trị cho _tracks. Các ví dụ MSDN và các cuốn sách tôi đã hiển thị mã theo cách này mà không có sự phân công - tôi đoán Linq To Sql sẽ quan tâm đến điều đó cho bạn. Có compier đã được ném ra cảnh báo nhưng vì Linq để SQL đã làm việc tôi figured tất cả mọi thứ đã được ok. Bạn chính xác về việc quên gán bài hát trong đối tượng Album. Tôi bỏ lỡ dán trong một khối mã cho thấy điều đó. Tôi đã thêm khối mã bị thiếu và tôi cũng sẽ ném mã triển khai thử nghiệm đơn vị của mình lên. Cảm ơn! – ColinICN

1

Đây là sửa chữa (làm việc) Album Class:

[Table(Name = "Albums")] 
public class Album 
{ 
    [Column(IsDbGenerated = true, IsPrimaryKey = true)] 
    public int AlbumID { get; set; } 
    [Column] 
    public string Title { get; set; } 

    private EntitySet<Track> _tracks = new EntitySet<Track>(); 

    [Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")] 
    public EntitySet<Track> Tracks 
    { 
     get { return _tracks; } 
     set { _tracks.Assign(value); } 
    } 
} 

[Table(Name = "Tracks")] 
public class Track 
{ 
    [Column(IsPrimaryKey = true)] 
    public int TrackID { get; set; } 
    [Column] 
    public string Title { get; set; } 
    [Column] 
    public int AlbumID { get; set; } 
} 

Các problme là tôi wasn' Tạo một thể hiện của đối tượng Album như Darin đã chỉ ra. Kiểm tra đơn vị hiện hoạt động chính xác. Tôi đã thử nghiệm cả với kho lưu trữ giả cũng như dữ liệu trực tiếp và mọi thứ hoạt động! Thật lạ khi các ví dụ MSDN (http://msdn.microsoft.com/en-us/library/bb425822.aspx) cũng không hiển thị bài tập.

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