是否可以使用Moq从实例获取模拟实例?

时间:2018-06-12 21:26:11

标签: c# moq

假设我有这个接口和这个类:

class readFile {


public fun getBuffer(sigId: String): ArrayList<DoubleArray> {


  val address="/data/data/com.example.amin.ecgs/Signals/Sig$sigId.bin"
    lateinit var buf: DoubleBuffer
    try {

        val rFile = RandomAccessFile(address, "rw")
        val inChannel = rFile.channel
        val buf_in = ByteBuffer.allocate(8 * 12 * 1002)
        buf_in.clear()
        inChannel.read(buf_in, 0)
        buf_in.rewind()
        buf = buf_in.asDoubleBuffer()

        inChannel.close()

    } catch (e: IOException) {
        e.printStackTrace()

    }

    return generateData(buf)

}

private fun generateData(buf: DoubleBuffer): ArrayList<DoubleArray> {

    val arrayList = ArrayList<DoubleArray>(12)

    for (n in 0..11) {
        val yb = DoubleArray(1002)
        buf.get(yb, n * 1002, (n + 1) * 1002)

        arrayList.add(yb)

    }
    buf.clear()
    return arrayList
}


}

所以我想知道我是否可以从GetScheduler方法获取模拟实例。我试过这样的事情:

public interface IScheduler
{
    void StopTimer();

    // some other methods
}

public class Scheduler : IScheduler
{
    private static readonly IScheduler scheduler = new Scheduler();

    private readonly Timer timer;

    public Scheduler()
    {
        refreshTimer = new Timer
        {
            Enabled = false,
            AutoReset = false
        };
    }

    public static IScheduler GetScheduler()
    {
        return scheduler;
    }

    public void StopTimer()
    {
        timer.Stop();
    }

    // some other methods
}

但没有用,它说“System.ArgumentException:对象实例不是由Moq创建的。”

请问任何建议?

在命令类中有

这样的东西:

[TestMethod]
public void Execute_ButtonClicked_StopTimer()
{
    // arrange
    var mockScheduler = Mock.Get(Scheduler.GetScheduler());
    var command = GetCommandInstance();

    // act
    command.Execute();

    // assert
    mockScheduler.Verify(m => m.StopTimer());
}

3 个答案:

答案 0 :(得分:4)

我提出了一种不同的方法,可以避免这样做......

Scheduler类正在实现单例模式来控制其构造。你需要能够抽象出依赖于IScheduler的东西而不是它的构造方式。所以 else 应该负责管理调度程序的构造:它本身不应该这样做,因为构造不是该类的责任(single responsibility principle)。

常见的方法是使用Gang of of Four Factory method patternservice locator pattern(例如Microsoft的UnityContainer)。这些中的任何一个都可以被指示将该类暴露为单例,使该类只是该类负责的实现。

Dependency Injection完成了拼图,因为当类注入了它们的依赖项时,它们本身就会从它们使用的东西的构造中抽象出来。因此,需要IScheduler的类会注入一个并使用它。

有了这些模式,在问题中做出请求的必要性就会消失,并导致代码明确地分离出来。

脚注:我知道这些模式看起来令人生畏,看起来它似乎为此做了很多努力,而且很难看到它的好处;但请相信我:尝试这个(我真的是说尝试一下,你不能只是半心半意地尝试,因为它在方法上是一个很大的改变)。我曾经像你发布的那样编写代码。我被建议看看这些模式。我有严重的疑虑,但我从未回头,现在我以这种方式编写所有代码。

答案 1 :(得分:0)

如果您在虚拟呼叫中包裹您要替换的呼叫,则可以这样做:

public class Scheduler : IScheduler
{
    private static readonly IScheduler scheduler = CreateScheduler();

    private readonly Timer timer;

    public Scheduler()
    {
        refreshTimer = new Timer
        {
            Enabled = false,
            AutoReset = false
        };
    }

    public static IScheduler GetScheduler()
    {
        return scheduler;
    }

    public void StopTimer()
    {
        timer.Stop();
    }

    public virtual IScheduler CreateScheduler()
    {
         return new Scheduler();
    }
    // some other methods
}

然后在您的单元测试课程中:

[TestClass]
public class TestClass
{
    [TestMethod]
    public void testMethod()
    {
        var scheduler = new Mock<Scheduler>();
        // you can now call .setup on the scheduler instance and use this mock.
        var sut = new SchedulerWrapper(scheduler.Object);

        ///var sut....sometests
    }
}

internal class SchedulerWrapper : Scheduler
{
    private Scheduler _scheduler;
    public SchedulerWrapper(Scheduler scheduler)
    {
         _scheduler;
    }
    public overrride IScheduler CreateScheduler()
    {
         return _scheduler;
    }
}

答案 2 :(得分:0)

目前还不清楚你要通过模拟测试什么。

如果测试需要检查私有静态字段,那么利用反射将是可行的方法,但最终会得到与Scheduler.GetScheduler()相同的结果。

从类型中获取私有静态字段的基本方法是:

var field = typeof(MyType).GetField( "MethodName", BindingFlags.NonPublic | BindingFlags.Static);
var fieldValue = field.GetValue(myTypeInstance);

模拟对虚拟地址表起作用(在运行时,MSIL检查增值税以查找要运行的方法的地址)。抽象基础和虚拟实例方法是可模拟的,接口也是如此。

如果虚拟添加到实例中StopTimer的签名中,它将是Mockable,这是从Mock<IScheduler>获得的所有内容。