如何测试具有静态依赖项的Singleton类 [英] How to test Singleton class that has a static dependency

查看:77
本文介绍了如何测试具有静态依赖项的Singleton类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Singleton类,该类使用Jon Skeet的线程安全Singleton模式,如TekPub视频中所示.该类表示MVC 3 UI中下拉菜单的参考数据的缓存列表.

I have a Singleton class that uses the thread-safe Singleton pattern from Jon Skeet as seen in the TekPub video. The class represents a cached list of reference data for dropdowns in an MVC 3 UI.

要获取列表数据,该类会在我的DAL中的静态类上调用一个静态方法.

To get the list data the class calls a static method on a static class in my DAL.

现在我要进行测试,我想在我的DAL类上实现一个接口,但是显然不能,因为它是静态的并且只有一个静态方法,所以没有要创建的接口.所以我想删除静态实现,以便可以进行界面操作.

Now I'm moving into testing an I want to implement an interface on my DAL class but obviously cannot because it is static and has only one static method so there's no interface to create. So I want to remove the static implementation so I can do the interface.

这样做,我无法从引用类中静态调用该方法,并且由于引用类是带有私有ctor的单例,因此无法注入接口.我该如何解决?如何将我的接口添加到引用类中,以便可以使用DI并可以通过模拟程序成功对其进行测试?

By doing so I can't call the method statically from the reference class and because the reference class is a singleton with a private ctor I can't inject the interface. How do I get around this? How do I get my interface into the reference class so that I can have DI and I can successfully test it with a mock?

这是我当前使用的DAL课程

Here is my DAL class in current form

public static class ListItemRepository {

    public static List<ReferenceDTO> All() {
        List<ReferenceDTO> fullList;
        ... /// populate list
        return fullList;
    }
}

这就是我想要的样子

public interface IListItemRepository {
    List<ReferenceDTO> All();
}

public class ListItemRepository : IListItemRepository {

    public List<ReferenceDTO> All() {
        List<ReferenceDTO> fullList;
        ... /// populate list
        return fullList;
    }
}

这是我的单例引用类,对静态方法的调用在CheckRefresh调用中

And here is my singleton reference class, the call to the static method is in the CheckRefresh call

public sealed class ListItemReference {

    private static readonly Lazy<ListItemReference> instance = 
        new Lazy<ListItemReference>(() => new ListItemReference(), true);

    private const int RefreshInterval = 60;
    private List<ReferenceDTO> cache;
    private DateTime nextRefreshDate = DateTime.MinValue;

    public static ListItemReference Instance {
        get { return instance.Value; }
    }

    public List<SelectListDTO> SelectList {
        get {
            var lst = GetSelectList();
            lst = ReferenceHelper.AddDefaultItemToList(lst);
            return lst;
        }
    }

    private ListItemReference() { }

    public ReferenceDTO GetByID(int id) {
        CheckRefresh();
        return cache.Find(item => item.ID == id);
    }

    public void InvalidateCache() {
        nextRefreshDate = DateTime.MinValue;
    }

    private List<SelectListDTO> GetSelectList() {
        CheckRefresh();
        var lst = new List<SelectListDTO>(cache.Count + 1);
        cache.ForEach(item => lst.Add(new SelectListDTO { ID = item.ID, Name = item.Name }));
        return lst;
    }

    private void CheckRefresh() {
        if (DateTime.Now <= nextRefreshDate) return;
        cache = ListItemRepository.All(); // Here is the call to the static class method
        nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
    }
    }
}

推荐答案

您可以使用基于实例的单例(不是基于静态的),可以为此声明接口.

You can use the singleton based on instance(not based on static), for which you can declare interface like this.

public interface IListItemRepository
{
    List<ReferenceDTO> All();
}


public class ListItemRepository : IListItemRepository
{
    static IListItemRepository _current = new ListItemRepository();

    public static IListItemRepository Current
    {
        get { return _current; }
    }

    public static void SetCurrent(IListItemRepository listItemRepository)
    {
        _current = listItemRepository;
    }

    public List<ReferenceDTO> All()
    {
        .....
    }
}

现在,您可以模拟IListItemRepository进行测试.

Now, you can mock IListItemRepository to test.

    public void Test()
    {
        //arrange
        //If Moq framework is used,
        var expected = new List<ReferneceDTO>{new ReferneceDTO()};

        var mock = new Mock<IListItemRepository>();           
        mock.Setup(x=>x.All()).Returns(expected);

        ListItemRepository.SetCurrent(mock.Object);

        //act
        var result = ListItemRepository.Current.All();

        //Assert
        Assert.IsSame(expected, result);
    }

这篇关于如何测试具有静态依赖项的Singleton类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆