【问题标题】:Using Moq with NUnit in C#在 C# 中将 Moq 与 NUnit 一起使用
【发布时间】:2019-08-02 07:15:03
【问题描述】:

我正在构建一个简单的机场程序,其中飞机只能在天气晴朗而不是暴风雨的情况下起飞/降落。这取决于天气类(它将天气在晴天和暴风雨之间随机化)。但是,对于我的测试,我想模拟天气,以便可以测试所有情况。

这是我的 Weather.cs:

using System;

namespace ClassNameWeather
{
    public class Weather
    {
        public Weather()
        {

        }

        public string Forecast()
        {
            Random random = new Random();
            var weather = random.Next(1, 11);
            if (weather == 1 || weather == 2)
            {
                return "stormy";
            }
            else
            {
                return "sunny";
            }
        }
    }
}

这是我的 Airport.cs:

using System;
using System.Collections.Generic;
using ClassNamePlane;
using ClassNameWeather;

namespace ClassNameAirport
{
    public class Airport
    {
        private string _AirportName { get; set; }
        public List<Plane> planes;
        private Weather _weather = new Weather();

        public Airport(string _airportName, Weather weather)
        {
            planes = new List<Plane>();
            _AirportName = _airportName;
        }

        public void Land(Plane plane)
        {
            if (_weather.Forecast() != "stormy")
            {
                planes.Add(plane);
                Console.WriteLine($"{ plane.Name } has landed at {_AirportName}");
            }
            else
            {
                throw new Exception("It's too stormy to land");
            }
        }

        public void TakeOff(Plane plane)
        {
            if (_weather.Forecast() != "stormy")
            {
                planes.Remove(plane);
                Console.WriteLine($"{ plane.Name } has departed from {_AirportName}");
            }
            else
            {
                throw new Exception("It's too stormy to take off");
            }
        }

        public int GetPlaneCount()
        {
            Console.WriteLine($"Number of planes at {_AirportName}: {planes.Count}");
            return planes.Count;
        }

        public void GetPlaneNames()
        {
            planes.ForEach(plane => Console.WriteLine((plane as Plane).Name));
        }

        public List<Plane> GetPlaneList()
        {
            return planes;
        }
    }
}

这是我尝试在其中使用模拟的测试:

using NUnit.Framework;
using ClassNameAirport;
using ClassNamePlane;
using ClassNameWeather;
using Moq;

namespace AirportTest
{
    public class AirportTest
    {
        Airport airport = new Airport("TestAirport", weather);
        Plane plane = new Plane("TestPlane");

        [Test]
        public void PlaneCanLand()
        {
            var weather = new Mock<Weather>();
            weather.Setup(x => x.Forecast()).Returns("sunny");
            airport.Land(plane);
            Assert.IsTrue(airport.planes.Contains(plane));
        }

        public void PlaneCanTakeOff()
        {
            airport.Land(plane);
            airport.TakeOff(plane);
            Assert.IsFalse(airport.planes.Contains(plane));
        }
    }
}

这条线:Airport airport = new Airport("TestAirport", weather); 不工作,说天气这个名字不存在。

谁能帮助我确保我正确使用了起订量?我是 C# 新手,非常感谢任何建议。

谢谢!

更新 我已解决此问题,但现在收到以下错误:

System.NotSupportedException : Unsupported expression: x => x.Forecast()
Non-overridable members (here: Weather.Forecast) may not be used in setup / verification expressions.

请问有人知道怎么解决吗?

【问题讨论】:

  • 你已经初始化了 Airport 类里面的 Weather,比如 private Weather _weather = new Weather(); weather 没有使用构造函数参数,你应该重写你的类,因为模拟不起作用
  • 谢谢@PavelAnikhouski 你介意解释一下重写课程是什么意思吗?

标签: c# unit-testing mocking nunit moq


【解决方案1】:

你可以介绍接口IWeatherlike

public interface IWeather
{
     string Forecast();
}

比在 Weather 类中实现它。将 IWeather 引用传递给 AirPort 类并为此设置一个模拟。

var weather = new Mock<IWeather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
...
var airport = new Airport("TestAirport", weather.Object)

并且不要在Airport类中直接初始化private Weather _weather = new Weather();(你的构造函数参数没有使用),这样做

public class Airport
{
    private string _AirportName { get; set; }
    public List<Plane> planes;
    private readonly IWeather _weather; 

    public Airport(string _airportName, IWeather weather)
    {
        planes = new List<Plane>();
        _weather = weather;
    }
...
}

【讨论】:

  • 感谢@PavelAnikhouski,这非常有帮助! :) 这似乎可行,我遇到的唯一麻烦是在Main 中声明我的 Airport 对象的新实例,因为它是一个接口。我将如何创建一个新的 Airport 对象?
  • @jordantomiko 您可以使用实现此接口的类的实例来初始化接口类型变量。 IWeather weather = new Weather();var weather = new Weather(); 机场相同 IAirport airport= new Airport();var airport= new Airport();
  • 谢谢!这就是我的想法,但我收到错误:Cannot implicitly convert type 'ClassNameWeather.Weather' to 'ClassNameWeather.IWeather'. An explicit conversion exists (are you missing a cast?) (CS0266) (Airport) 当我尝试在Main中初始化我的机场的新实例时@
  • @jordantomiko 您应该在Airport 类中使用接口类型引用IWeather,而不是Weather 类,就像我在答案中发布的那样。并初始化var airport = new Airport("TestAirport", new Weather());
  • 谢谢@PavelAnikhouski - 我按照你在回答中所说的做了所有这些,但我仍然得到那个错误。也许是我引入天气界面的方式?它是否需要位于 Weather.cs 中的特定位置?
【解决方案2】:

您尚未声明变量weather。我建议您创建一个 Initialize 方法并将其属性与TestInitialze

[TestInitialize]
public void TestInitialize() 
{
    var weather = new Mock<Weather>();
    var airport = new Airport("TestAirport", weather)
}

【讨论】:

  • 谢谢 - 我试过了,但没用。一开始它不喜欢TestInitialize,所以我尝试了NUnit的[TestFixtureSetUp],但它仍然对天气参数不满意:(
  • 错误说明了什么?你显然没有在这里声明天气变量:Airport airport = new Airport("TestAirport", weather); Plane plane = new Plane("TestPlane");
  • 别担心,我已经让它工作了(这与我将它放在我的程序中的位置有关) - 谢谢你的帮助。我现在收到以下错误:System.NotSupportedException : Unsupported expression: x =&gt; x.Forecast() Non-overridable members (here: Weather.Forecast) may not be used in setup / verification expressions. 但我会更新我原来的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 2011-12-14
相关资源
最近更新 更多