C# 模拟测试 - 最小起订量列表不能是“foreach”,告诉“NullReferenceException”

本文关键字:不能 NullReferenceException foreach 列表 告诉 测试 模拟 | 更新日期: 2023-09-27 18:32:36

环境: NUnit 2.6.4;NUnit 测试适配器 2.0.0;最小起订量 4.2.1;视觉标准 4.6;

短:我安装了家庭安全系统,其中有供应商的传感器,警报,PowerSuply,显示器的界面。我想测试它的实现。我想测试"系统检查通过"子例程。

我模拟ISensor列表并构造"SecurityController",然后运行"SystemCheckPass"子例程。当它执行到"SystemCheckPass"子例程时,"foreach"无法正常运行,它说"NullReferenceException"。

在 ISensors 的模拟列表上的 'foreach' 循环的测试函数中,这一切都很好。简单地将 ref 传递给"安全控制器"后,"列表"的"foreach"循环"找不到其元素的"ref"。我对此感到非常困惑。

有人能告诉我为什么吗?

安全控制器的实现。

using System;
using System.Collections.Generic;
using HomeSecuritySystem.Sensors;
using HomeSecuritySystem.Comms;
using HomeSecuritySystem.Power;
using HomeSecuritySystem.Display;
using HomeSecuritySystem.Alarm;
using HomeSecuritySystem.Report;
using System.Threading;
using System.Diagnostics;
namespace HomeSecuritySystem
{
    public class SecurityController : ControllerBase
    {
        public int Value;
        public ICollection<ISensor> sensors;
        public IComms comms;
        public IPowerSupply powerSupply;
        public IAlarm alarm;
        public IDisplay display;
        public SecurityController(ICollection<ISensor> sensors, IComms comms, IPowerSupply powerSupply, IAlarm alarm, IDisplay display)
            : base(sensors, comms, powerSupply, alarm, display)
        {
            this.sensors = sensors;
            this.comms = comms;
            this.powerSupply = powerSupply;
            this.alarm = alarm;
            this.display = display;
            // bind the power down event when system initials, because it never changes.
            powerSupply.OnNoPower += new Events.NoPowerEvent(PowerSupplyNoPower);
            // initialize 
            IsArmedLastSate = IsArmed;
            IsStayLastSate = IsStay;
        }
        public bool SystemCheckPass()
        {
            // <---- begin system check
            bool systemCheckPass = true;
            // check the device power except sensors 
            if (alarm.IsOn == false || comms.IsOn == false || powerSupply.IsOn == false)
            {
                // part of system check, power is off, system check fail
                systemCheckPass = false;
            }


            // check power of sensors
            foreach (ISensor sensor in sensors)
            {
                if (sensor.IsOn == false)
                    systemCheckPass = false;
            }
            /*
            // check the battery of sensors
            foreach (ISensor sensor in sensors)
            {
                switch (sensor.Type)
                {
                    // part of system check, motion sensor's battery is low, system check fail
                    case Report.SensorType.Motion:
                        IMotionSensor motionSensor = (IMotionSensor)(sensor);
                        if (motionSensor.IsLowBattery == true)
                        {
                            systemCheckPass = false;
                        }
                        break;
                    // part of system check, smoke sensor's battery is low, system check fail
                    case Report.SensorType.Smoke:
                        ISmokeSensor smokeSensor = (ISmokeSensor)(sensor);
                        if (smokeSensor.IsLowBattery == true)
                        {
                            systemCheckPass = false;
                        }
                        break;
                    default:
                        // so far, only two kinds of sensors
                        throw new Exception("no exit sensor type!");
                }
            }
            //check the battery of power supply
            if (powerSupply.IsLowBattery)
            {
                systemCheckPass = false;
            }
            */
            // system check over ---->
            return systemCheckPass;
        }
        public override void SystemCheck()
        {
            // <---- begin system check
            bool systemCheckPass = true;
            List<int> lowBatterySensorIDList = new List<int>();
            // check the device power except sensors 
            if (alarm.IsOn == false || comms.IsOn == false || powerSupply.IsOn == false)
            {
                // part of system check, power is off, system check fail
                systemCheckPass = false;
            }
            // check power of sensors
            foreach (ISensor sensor in sensors)
            {
                if (sensor.IsOn == false)
                    systemCheckPass = false;
            }
            bool lowBatterySensorExist = false;
            // check the battery of sensors
            foreach (ISensor sensor in sensors)
            {
                switch (sensor.Type)
                {
                    // part of system check, motion sensor's battery is low, system check fail
                    case Report.SensorType.Motion:
                        IMotionSensor motionSensor = (IMotionSensor)(sensor);
                        if (motionSensor.IsLowBattery == true)
                        {
                            lowBatterySensorIDList.Add(motionSensor.Id);
                            systemCheckPass = false;
                            lowBatterySensorExist = true;
                        }
                        break;
                    // part of system check, smoke sensor's battery is low, system check fail
                    case Report.SensorType.Smoke:
                        ISmokeSensor smokeSensor = (ISmokeSensor)(sensor);
                        if (smokeSensor.IsLowBattery == true)
                        {
                            lowBatterySensorIDList.Add(smokeSensor.Id);
                            systemCheckPass = false;
                            lowBatterySensorExist = true;
                        }
                        break;
                    default:
                        // so far, only two kinds of sensors
                        throw new Exception("no exit sensor type!");
                }
            }
            //check the battery of power supply
            bool BatteryOfPowSupplyIsLow = false;
            if (powerSupply.IsLowBattery)
            {
                systemCheckPass = false;
                BatteryOfPowSupplyIsLow = true;
            }
            // system check over ---->
            // <---- report begin
            if (systemCheckPass)
            {
                display.ShowSystemReady();
            }
            else
            {
                display.ShowSystemNotReady();
            }
            if (lowBatterySensorExist)
            {
                display.ShowSensorLowBattery(lowBatterySensorIDList);
            }
            if (BatteryOfPowSupplyIsLow)
            {
                display.ShowPowerSupplyLowBattery();
            }
            // report end --->
        }
        public override void ClearMemory()
        {
            display.ClearSentReport();
            display.ClearAlarmSound();
            display.ClearSystemArmed();
            foreach (ISensor sensor in sensors)
            {
                display.ClearSensorDetected(sensor.Id);
            }
        }
        // bind to event sensor.OnDetectionStateChanged
        public void ArmSensorDetected(ISensor sensor)
        {
            if (sensor.Detected)
            {
                alarm.SoundAlarm();
                display.ShowAlarmSound();
                display.ShowSensorDetected(sensor.Id);
                Report.Report report = new Report.Report();
                report.SensorId = sensor.Id;
                report.SensorType = sensor.Type;
                report.Time = new DateTime();
                report.Type = Report.ReportType.Intrusion;
                display.ShowSentReport("sensor detected");
                comms.InformSecurity("sensor detected");
            }
        }
        public void ArmStaySensorDetected(ISensor sensor)
        {
            if (sensor.Type == Report.SensorType.Motion)
            {
                IMotionSensor motionSensor = (IMotionSensor)(sensor);
                if (motionSensor.Detected && motionSensor.IsPerimeterSensor)
                {
                    alarm.SoundAlarm();
                    display.ShowAlarmSound();
                    display.ShowSensorDetected(sensor.Id);
                    display.ShowSentReport("sensor detected");
                    comms.InformSecurity("sensor detected");
                }
            }
        }
        public void SmokeSensorDetected(ISensor sensor)
        {
            if (sensor.Type == Report.SensorType.Smoke)
            {
                ISmokeSensor smokeSensor = (ISmokeSensor)(sensor);
                if (smokeSensor.Detected)
                {
                    Report.Report report = new Report.Report();
                    report.SensorId = sensor.Id;
                    report.SensorType = sensor.Type;
                    report.Time = new DateTime();
                    report.Type = Report.ReportType.Smoke;
                    alarm.SoundAlarm();
                    display.ShowAlarmSound();
                    display.ShowSensorDetected(sensor.Id);
                    display.ShowSentReport("sensor detected");
                    comms.InformSecurity("sensor detected");
                }
            }
        }
        public void PowerSupplyNoPower()
        {
            Report.Report report = new Report.Report();
            report.Time = new DateTime();
            report.Type = Report.ReportType.NoPower;
            comms.InformSecurity("power down");
            display.ShowSentReport("power down");
        }
        private bool IsArmedLastSate;
        private bool IsStayLastSate;
        private void DelegateHandling()
        {
            foreach (ISensor sensor in sensors)
            {
                sensor.OnDetectionStateChanged += new Events.SensorDetectionStateChangeEvent(ArmSensorDetected);
            }
            if (IsArmed == true && IsStay == false)
            {
                foreach (ISensor sensor in sensors)
                {
                    sensor.OnDetectionStateChanged += new Events.SensorDetectionStateChangeEvent(ArmSensorDetected);
                }
            }
            else if (IsArmed == true && IsStay == true)
            {
                foreach (ISensor sensor in sensors)
                {
                    sensor.OnDetectionStateChanged += new Events.SensorDetectionStateChangeEvent(ArmStaySensorDetected);
                }
            }
            else if (IsArmed == false && IsStay == false)
            {
                alarm.StopAlarm();
            }
            foreach (ISensor sensor in sensors)
            {
                sensor.OnDetectionStateChanged += new Events.SensorDetectionStateChangeEvent(SmokeSensorDetected);
            }
        }
        public void Run()
        {
            // initial delegete bind
            DelegateHandling();
            //delegate sensor
            for (;;)
            {
                Thread.Sleep(100);
                SystemCheck();
                if (IsArmedLastSate != IsArmed || IsStayLastSate != IsStay)
                {
                    // when Security Controller change mode, rebind all sensors' delegete.
                    DelegateHandling();
                    IsArmedLastSate = IsArmed;
                    IsStayLastSate = IsStay;
                }
            }
        }
        static int Main(string[] args)
        {
            //... 
            return 0;
        }
    }
}

我使用 NUnit 和 Moq 进行单元测试。系统检查通过的单元测试。

using HomeSecuritySystem.Alarm;
using HomeSecuritySystem.Sensors;
using Moq;
using System.Collections.Generic;
namespace HomeSecuritySystem
{
    using Comms;
    using Display;
    using NUnit.Framework;
    using Power;
    [TestFixture]
    public class SecurityControllerTest
    {
        [Test]
        public void Test_System_Check()
        {
            //arrange
            Mock<IMotionSensor> mockMotionSensor = new Mock<IMotionSensor>();
            mockMotionSensor.SetupGet(t => t.IsLowBattery).Returns(true);
            //mock sensors
            Mock<List<ISensor>> mockSensors = new Mock<List<ISensor>>();
            mockSensors.Object.Add(mockMotionSensor.Object);
            foreach (ISensor sensor in mockSensors.Object)
            {
                if (sensor.IsOn == false)
                    ;
            }
            Mock<IComms> mockComms = new Mock<IComms>();
            mockComms.SetupGet(t => t.IsOn).Returns(true);
            Mock<IPowerSupply> mockPowerSupply = new Mock<IPowerSupply>();
            mockPowerSupply.SetupGet(t => t.IsOn).Returns(true);
            Mock<IAlarm> mockAlarm = new Mock<IAlarm>();
            mockAlarm.SetupGet(t => t.IsOn).Returns(true);
            Mock<IDisplay> mockDisplay = new Mock<IDisplay>();
            SecurityController securityController = new SecurityController(mockSensors.Object, mockComms.Object, mockPowerSupply.Object, mockAlarm.Object, mockDisplay.Object);
            //act
            Assert.AreEqual(securityController.SystemCheckPass(), true);
        }
    }
}

NUnit 测试框架给出的错误:

Test Name:  Test_System_Check
Test FullName:  HomeSecuritySystem.SecurityControllerTest.Test_System_Check
Test Source:    C:'Users'OEM'Documents'Visual Studio 2015'Projects'HomeSecurityController'HomeSecurityController.UnitTest'SecurityControllerTest.cs : line 17
    Test Outcome:   Failed
    Test Duration:  0:00:00.569
Result StackTrace:  
at HomeSecuritySystem.SecurityController.SystemCheckPass() in C:'Users'OEM'Documents'Visual Studio 2015'Projects'HomeSecurityController'HomeSecurityController'SecurityController.cs:line 58
at HomeSecuritySystem.SecurityControllerTest.Test_System_Check() in C:'Users'OEM'Documents'Visual Studio 2015'Projects'HomeSecurityController'HomeSecurityController.UnitTest'SecurityControllerTest.cs:line 42
Result Message: System.NullReferenceException : Object reference not set to an instance of an object.

C# 模拟测试 - 最小起订量列表不能是“foreach”,告诉“NullReferenceException”

主要是因为GetEnumerator是为你IList<T>而调用的,你没有嘲笑。

我建议不要嘲笑像IList<T>这样的类似集合的对象。只需传递它们的实际实现即可。否则,就像您正在测试foreach是否有效。