如何使用列表来存储Mock对象

时间:2016-02-12 16:05:35

标签: c# moq

我是这个Moq社区的新人。

我想知道有没有办法将A(Mock)的继承对象放到Mock接口A的列表中?

例如,假设我们有

Class ClientA :IMyClient{...}   //has override virtual codes
Class ClientB :IMyClient{...}

 List<Mock<IMyClient>> mockClients = new List<Mock<IMyClient>>();

无论如何,我可以做这样的事情:

var mockClientA = new Mock<ClientA>();
mockClients.Add(mockClientA);

我可能没有走上正轨。需要一些帮助。感谢。

=================================

设置

   // setup everyone to Free
    actualManager.Status = Status.Free;
    foreach (var mock in mockClients) {
        mock.Object.Status = Status.Free;
        actualManager.AddClient(mock.Object);
    }

测试

    Assert.AreEqual(Status.Free, actualManager.Status); // pass
    var firstClient = mockClients.First();
    IMyClient actualFirstClient  = SetClientToTriggerOutsideCallbacks(firstClient);
    firstClient.Status = Status.Busy;

    // busy, since the first client is busy now.
    Assert.AreEqual(Status.Busy, actualManager.Status);  //pass
    SessionSwitchEventArgs e = new SessionSwitchEventArgs(SessionSwitchReason.SessionLock);
    actualManager.SystemEvents_SessionSwitch(null, e);
    Assert.AreEqual(Status.Away, actualManager.Status);   //not pass

我试图检查状态更改对不同客户端的影响,因此我尝试使用列表来存储所有客户端。 问题是:如果第一个客户端不是ClientA类型,则actualManager.SystemEvents_SessionSwitch(null, e);无法正常工作。

2 个答案:

答案 0 :(得分:0)

First of all - why do we need mocks and stubs? Because our SUT (System Under Test, the object which you are testing) often has some dependencies. We cannot use real dependencies which we have in production code, because we will not be able to tell the reason why test is passing or failing. It might be error in SUT or in dependency. So we should provide something instead of real dependency which will be reliable. I.e. it should not produce any unexpected errors no matter how you change implementation of real dependencies. That's why we use stubs and mocks.

But what's the difference between them? Stubs are used in tests which do state verification. I.e. when you after exercising SUT verify state of SUT and (sometime) stub. Stub can be very simple. You can just implement dependency interface and use auto-properties without any logic inside. It's enough for you to setup some value, SUT will read/write something into stub. At the end you will check state. You will not check what operations were performed.

Behavior verification is very different. It focuses on interaction between SUT and dependencies. We setup some expectations for mock object. It's not same as setting up some properties with fake data. With mock you setup the fact that property or method should be called, and correct parameters should be passed. With stub you don't check whether it was called. You just make call possible and check state at the end.

So.. what you are doing here is state verification with mocks. Which is not how mocks supposed to be used. I.e. you setup status of clients and then check state of manager. Instead of using Moq following simple implementation completely satisfies your needs:

marker-end

You can set status. Manager can read it. You can check manager's state. If you are going to use mocks, you should use behavior verification (otherwise it's just overkill). It's hard to tell what is the purpose of your manager class and how it checks status of clients. If you'll add this information I'll add some behavior verification test for your manager.

And regarding your question about putting mocks of different types into list - you cannot do that (well, only if you have list of objects). And it makes no sense. If some SUT expects list of dependencies, then you should put mock objects (accessible via public class ClientStub : IMyClient { public Status Status { get; set; } // some other members here } property of mock) into that list. That's the difference between Moq and RhinoMocks.

答案 1 :(得分:0)

谢谢@SergeyBerezovskiy。我甚至没有朝着正确的方向前进。谢谢你的ref链接。 我重写了C#版本中的链接示例并进行了测试。我认为这有助于我了解Mock。如果我在这里做了什么坏事,请告诉我。感谢。

WareHouse.cs

$csv = import-csv c:\employees.csv
$First = read-host 'What is the users first name?'
$Last = read-host 'What is the users last name?'
$csv | Where-Object { $_.last -eq $Last -and $_.'First Name' -eq $First } |
Select-Object -Expand 'Payroll Department Number'

Order.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test {
    public class WareHouse {
    private Dictionary<string, int> wareHouseRepo = new Dictionary<string, int>();

    public void Add(string location, int number) {
    //null add
    if (wareHouseRepo.ContainsKey(location)) {
    int inventory_Old = wareHouseRepo[location];
        wareHouseRepo[location] = inventory_Old + number;
    } else {
         wareHouseRepo.Add(location, number);
    }
}


public virtual bool FillIt(string location, int number) {
    if (wareHouseRepo.ContainsKey(location)) {
        int inventory = wareHouseRepo[location];
        if(inventory >= number){
            wareHouseRepo[location] = inventory - number;
            return true;
        }else{
            return false;
        }
    } else {
        return false;
    }
}
}    

public int GetInventory(string location) {
    if (wareHouseRepo.ContainsKey(location)) {
        return wareHouseRepo[location];              
    } else {
        return 0;
    }
    }
}

TestWareHouse.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

    namespace Test {
        class Order {
            private string location = "";
            private int orderNum = 0;

            private bool filled = true;

            public Order(string loc, int num) {
                this.location = loc;
                this.orderNum = num;
            }

            public void Fill(WareHouse wh){
                if (wh.FillIt(location, orderNum)) {
                    filled = true;
                } else {
                    filled = false;
                }
            }

            public bool isFilled() {
                return filled;
            }

        }
    }