簡體   English   中英

在dut方法中使用的模擬lambda表達式

[英]mocking lambda expressions that are used in methods of the dut

我有一個下面要進行單元測試的方法:

public string GetReferentie(string prefix)
{
        IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
        var dateparameterGetal = parameterGetalRepository
            .Query(o => o.parameter=="Datum")
            .Select()
            .Single();
        var ordertellerparametergetal = parameterGetalRepository
                .Query(o => o.parameter == "orderteller")
                .Select()
                .Single();
        DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
        int orderteller=0;
        if (date == DateTime.Today)
        {
            orderteller = int.Parse(ordertellerparametergetal.parameterwaarde); 
        }
        else
        {
            dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
            orderteller = 0;
        }
        orderteller++;

        ordertellerparametergetal.parameterwaarde = orderteller.ToString();

        string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);

        return result;
}

這里的問題是,我正在使用2個lambda表達式,這使模擬變得很困難,因為我在stackoverflow中找到的大多數解決方案都制定了基於忽略正在使用的lambda的解決方案。

您如何處理? 注意,我有解決方案。 接下來,我將其發布為答案。

有時對於單元測試,必須在DUT的設計中務實,並且可能在類中添加僅用於單元測試的內容。 我從上面修改了該類,以使lambda表達式可變,並允許通過getter訪問這些表達式。 這樣,單元測試可以訪問getter,因此模擬程序可以真正檢查要傳遞的lambda。 這里有足夠的談話是代碼:

public class ReferentieBuilder : IReferentieBuilder
{
    private readonly IUnitOfWorkAsync _unitOfWork;
    private static readonly Expression<Func<ParameterGetal, bool>> _datumExpression = o => o.parameter=="Datum";
    private static readonly Expression<Func<ParameterGetal, bool>> _ordertellerExpression = o => o.parameter == "orderteller";

    public ReferentieBuilder(IUnitOfWorkAsync unitOfWork)
    {
        if (unitOfWork == null)
        {
            throw new ArgumentNullException("unitOfWork");
        }
        _unitOfWork = unitOfWork;
    }

    public static Expression<Func<ParameterGetal, bool>> DatumExpression
    {
        get { return _datumExpression;}
    }

    public static Expression<Func<ParameterGetal, bool>> OrderTellerExpression
    {
        get { return _ordertellerExpression; }
    }

    public string GetReferentie(string prefix)
    {
        IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
        Debug.Assert(parameterGetalRepository!=null);
        var dateparameterGetal = parameterGetalRepository
            .Query(DatumExpression)
            .Select()
            .Single();
        var ordertellerparametergetal = parameterGetalRepository
                .Query(OrderTellerExpression)
                .Select()
                .Single();
        DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
        int orderteller=0;
        if (date == DateTime.Today)
        {
            orderteller = int.Parse(ordertellerparametergetal.parameterwaarde); 
        }
        else
        {
            dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
            orderteller = 0;
        }
        orderteller++;

        ordertellerparametergetal.parameterwaarde = orderteller.ToString();

        string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);

        return result;
    }
}

請參見我已經偽裝了兩個靜態只讀成員變量,並預見了靜態只讀屬性。 DatumExpression和OrderTellerExpression。

單元測試代碼將變成這樣:

[TestFixture]
class ReferentieBuilderTests
{
    private IUnitOfWorkAsync _unitOfWork;

    [SetUp]
    public void setup()
    {
        List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
        {
            new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
        };

        List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
        {
            new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
        };

        IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
        IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
        IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
        _unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();

        _unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
            .Return(parametergetalrepository);
        parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.DatumExpression))
            .Return(datefluent);
        parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.OrderTellerExpression))
            .Return(tellerfluent);
        datefluent.Stub(q => q.Select())
            .Return(dateParameterGetallen);
        tellerfluent.Stub(q => q.Select())
            .Return(tellerParameterGetallen);
    }

    [Test]
    public void GetFirstReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
        Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
    }

    [Test]
    public void GetSecondReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        referentieBuilder.GetReferentie(prefix);
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
        Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
    }

    [Test]
    public void GetThirdReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        referentieBuilder.GetReferentie(prefix);
        referentieBuilder.GetReferentie(prefix);
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
        Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
    }
}

這里的竅門是,該模擬使用的是ReferentieBuilder.DatumExpression和ReferentieBuilder.OrderTellerExpression,而不是在單元測試中以硬編碼方式傳遞相同的lambda表達式。 這具有不重復的額外優點。 通過為允許單元測試訪問的lambda表達式添加只讀屬性,代碼並沒有那么復雜。

請不要過多地判斷代碼的邏輯。 它正在嘗試生成一個從每天1開始的運行編號。 上次訪問該函數的時間以及最后一個數字也存儲在數據庫中。 這是根據要求,我也不喜歡。

也可以使用Eugene注釋以下解決方案:

[TestFixture]
class ReferentieBuilderTests
{
    private IUnitOfWorkAsync _unitOfWork;

    [SetUp]
    public void setup()
    {
        List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
        {
            new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
        };

        List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
        {
            new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
        };

        IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
        IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
        IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
        _unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();

        _unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
            .Return(parametergetalrepository);
        parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "Datum"))))
            .Return(datefluent);
        parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "orderteller"))))
            .Return(tellerfluent);
        datefluent.Stub(q => q.Select())
            .Return(dateParameterGetallen);
        tellerfluent.Stub(q => q.Select())
            .Return(tellerParameterGetallen);
    }

    [Test]
    public void GetFirstReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
        Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
    }

    [Test]
    public void GetSecondReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        referentieBuilder.GetReferentie(prefix);
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
        Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
    }

    [Test]
    public void GetThirdReferentieOfDay_returnsCorrectReferentie()
    {
        ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);

        string prefix = "P";
        referentieBuilder.GetReferentie(prefix);
        referentieBuilder.GetReferentie(prefix);
        DateTime today = DateTime.Today;
        string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
        Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
    }
}

可以在這里找到lambda表達式比較器: 測試lambda表達式相等性的最有效方法

使用鏈接的更新。 使用此解決方案,無需在DUT上進行任何更新,即,無需表達式只讀屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM