0

TekPub ビデオで見られるように、Jon Skeet のスレッドセーフな Singleton パターンを使用する Singleton クラスがあります。このクラスは、MVC 3 UI のドロップダウンのキャッシュされた参照データのリストを表します。

リスト データを取得するために、クラスは DAL の静的クラスで静的メソッドを呼び出します。

DALクラスにインターフェースを実装したいのですが、静的で静的メソッドが1つしかないため、作成するインターフェースがないため、明らかにできません。そのため、インターフェイスを実行できるように、静的実装を削除したいと考えています。

そうすることで、参照クラスからメソッドを静的に呼び出すことができなくなり、参照クラスがプライベート ctor を持つシングルトンであるため、インターフェイスを注入できなくなります。どうすればこれを回避できますか? インターフェイスを参照クラスに取得して、DI を使用し、モックで正常にテストできるようにするにはどうすればよいですか?

これが現在の形式の私のDALクラスです

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呼び出しにあります

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);
    }
    }
}
4

3 に答える 3

1

インスタンスに基づくシングルトン(静的に基づくものではない)を使用でき、このようにインターフェースを宣言できます。

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をモックしてテストできます。

    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);
    }
于 2012-06-07T20:15:45.043 に答える
0

どの DI フレームワークを使用していますか? あなたの答えに応じて、IOC コンテナーは単一インスタンス化を処理できる必要があるため、キャッシュ クラスに独自のシングルトン パターンを実装する必要はありません。コードではすべてをインスタンス化されたクラスとして扱いますが、DI フレームワーク マッピングでは、キャッシュ クラスのインスタンスを 1 つだけ作成するように指定できます。

于 2012-06-07T18:09:54.577 に答える
0

それをテストする 1 つの方法は、追加のプロパティを追加して ListItemReference をリファクタリングする場合です。

public sealed class ListItemReference {
    ...
    public Func<List<ReferenceDTO>> References = () => ListItemRepository.All();
    ...
    private void CheckRefresh() {
        if (DateTime.Now <= nextRefreshDate) return;
        cache = References();
        nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
    }
}

そして、テストで次のことができます。

ListItemReference listReferences = new ListItemReference();
listReferences.References = () => new List<ReferenceDTO>(); //here you can return any mock data

もちろん、これは一時的な解決策であり、IoC/DI を使用して静的を取り除くことをお勧めします。

于 2012-06-07T19:06:18.713 に答える