asp.net-mvc - 如何为 MVC 创建具有一对多关联的假存储库

标签 asp.net-mvc unit-testing repository-pattern

我正在尝试使用具有一对多关系的类对象创建一个用于单元测试的假存储库。我正在使用 ASP.NET MVC 和 Linq to SQL。我的引用资料是 Steven Sanderson 的“Pro ASP.NET MVC Framework”一书。

我创建了具有关联的实体类:

[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; }
}

以及存储库的抽象接口(interface):
public interface IMusicRepository
{
    IQueryable<Album> Albums { get; }
    IQueryable<Track> Tracks { get; }
}

我能够为专辑创建一个假存储库 - 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(); }
    }

}

只要我不尝试访问任何轨道,它就可以正常工作。换句话说,Album.Title 有效,但访问 Album.Tracks.Count() 将生成 null Reference 异常。我不确定 Linq-To-SQL 或 Linq-To-Objects 是否会拾取关联并自动将其与假对象一起使用。

问题是,无论我尝试什么,似乎都无法将轨道分配给专辑类。我知道 EntitySet 基于 IEnumerable,但是将 Enumerable 列表转换为 EntitySet 是一个挑战。

Album 期待一个 EntitySet 但我能够传递它的唯一方法是通过自定义助手:
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;
    }
}

这和我来的一样接近:
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(); }
    }

}

但是,当我尝试访问 Album.Tracks 时,我得到

System.NullReferenceException : Object reference not set to an instance of an object.



这是实现/单元测试:
    [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!");
    }

我花了几天时间寻找这个问题的答案,但没有找到任何示例,所以如果有人能够发布一个有效的答案示例,我相信其他人也会感兴趣。

我对 MVC 和单元测试很陌生,所以请放轻松。我手头也有 IoC 和 Moq,但我对这些知之甚少,但我计划在这个项目中同时使用这两者。如果有更好的方法来做到这一点,那么我全神贯注!谢谢。

最佳答案

Album类似乎有点奇怪,尤其是这部分:

private EntitySet<Track> _tracks;

[Association(Storage = "_tracks", ThisKey = "AlbumID", OtherKey = "AlbumID")]
public EntitySet<Track> Tracks
{
    get { return _tracks; }
    set { _tracks.Assign(value); }
}
_tracks私有(private)成员(member)是 从不分配一个值,然后调用 Assign在引发异常的 setter 中对其进行方法。顺便说一句,编译器应该警告过你。在调用 Assign 之前,您可以尝试在 setter 中提供默认值或检查 null。方法:
private EntitySet<Track> _tracks = new EntitySet<Track>();

除此之外,您转换 IEnumerable<T> 的扩展方法至EntitySet<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();

关于asp.net-mvc - 如何为 MVC 创建具有一对多关联的假存储库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2359763/

相关文章:

c# - 如何在不实际执行查询的情况下测试查询数据库的方法?

c# - EF 存储库模式多对多插入

java - 如何使用 Java Spring 的泛型类型来实现存储库模式

asp.net - 使用 IIS 而不是 IIS Express 会加快本地运行的 VS2013 WebAP 应用程序的启动时间吗?

java - EasyMock 期望使用 Collection 类型的参数调用方法

asp.net - ASP.NET 和 ASP.NET MVC 有什么区别?

unit-testing - Grails Spock单元测试的重定向和渲染

php - 在 Laravel 5.x 中使用存储库模式时,我们应该只在 Controller 中使用叙述方法吗?

javascript 下拉菜单和函数

c# - 如何为电子邮件消息中的占位符编码?