C#模拟测试 - Moq列表不能预告',告诉' NullReferenceException'

时间:2016-01-31 22:50:48

标签: c# nunit moq

环境:NUnit 2.6.4; NUnit TestAdapter 2.0.0; Moq 4.2.1; VisualStdio 4.6;

简介: 我实现了一个HomeSecuritySystem,其中包含供应商的传感器,报警器,PowerSuply,显示器接口。我想测试它的实现。我想测试一下SystemCheckPass'子程序。

我模拟了一个ISensor列表并构建了' SecurityController'然后我运行了SystemCheckPass'子程序。当它执行到SystemCheckPass'子程序,' foreach'没有正确运行,它说'NullReferenceException'。

对于“foreach”的测试功能来说,这一切都很好。循环在ISensors的MockList上。只需将参考文献传递给' SecurityController',就可以了解' foreach' '环路' ' list'无法找到' 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来进行UnitTest。系统检查通行证的单元测试。

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 Framework提供的错误:

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.

1 个答案:

答案 0 :(得分:3)

这主要是因为你GetEnumerator调用了IList<T>,你没有模仿。

我建议不要模拟像IList<T>这样的类似集合的对象。只需传递它们的实际实现。否则,就像你正在测试foreach的工作原理。