C# 模拟测试-最小起订量清单can';不可能是';foreach';,被告知';NullReferenceException';

C# 模拟测试-最小起订量清单can';不可能是';foreach';,被告知';NullReferenceException';,c#,nunit,moq,C#,Nunit,Moq,环境:NUnit 2.6.4;NUnit TestAdapter 2.0.0;最小起订量4.2.1;第4.6条 简介: 我实现了一个家庭安全系统,其中有供应商的传感器、报警器、电源、显示器接口。我想测试它的实现。我想测试“SystemCheckPass”子例程 我模拟一个ISensor列表并构造“SecurityController”,然后运行“SystemCheckPass”子例程。当它在“SystemCheckPass”子例程中执行时,“foreach”无法正常运行,它显示为“NullRef

环境:NUnit 2.6.4;NUnit TestAdapter 2.0.0;最小起订量4.2.1;第4.6条

简介: 我实现了一个家庭安全系统,其中有供应商的传感器、报警器、电源、显示器接口。我想测试它的实现。我想测试“SystemCheckPass”子例程

我模拟一个ISensor列表并构造“SecurityController”,然后运行“SystemCheckPass”子例程。当它在“SystemCheckPass”子例程中执行时,“foreach”无法正常运行,它显示为“NullReferenceException”

在ISensor模拟列表上的“foreach”循环的测试函数中,这一切都很好。简单地将ref传递给“SecurityController”之后,“list”的“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;
        }
    }
}
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);
        }
    }
}

这主要是因为
GetEnumerator
是为您的
IList
调用的,您没有模拟它


我建议不要模拟像
IList
这样的对象。只需传递它们的实际实现即可。否则,就好像您正在测试
foreach
是否有效。

是。我将测试代码更改为
List Sensors=new List();添加(mockMotionSensor.Object)然后它就可以正常工作了。谢谢。我对你使用Visual Studio 4.6印象深刻…@PatrickQuirk“印象深刻”
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.