ইউনিট টেস্টিং যে ইভেন্টগুলি সি # তে উত্থাপিত হয়েছে (ক্রমে)


160

আমার কিছু কোড রয়েছে যা PropertyChangedইভেন্টগুলি উত্থাপন করে এবং আমি ঘটনাটি সঠিকভাবে উত্থাপিত হচ্ছে কিনা তা ইউনিট পরীক্ষায় সক্ষম হতে চাই।

ইভেন্টগুলি উত্থাপন করছে এমন কোডটি এর মতো

public class MyClass : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;  

   protected void NotifyPropertyChanged(String info)
   {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
   }  

   public string MyProperty
   {
       set
       {
           if (_myProperty != value)
           {
               _myProperty = value;
               NotifyPropertyChanged("MyProperty");
           }
       }
   }
}

আমি আমার ইউনিট পরীক্ষায় নিম্নলিখিত কোড থেকে একটি দুর্দান্ত সবুজ পরীক্ষা পেয়েছি, এতে প্রতিনিধিরা ব্যবহার করে:

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    string actual = null;
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
         actual = e.PropertyName;
    };

    myClass.MyProperty = "testing";
    Assert.IsNotNull(actual);
    Assert.AreEqual("MyProperty", actual);
}

যাইহোক, আমি যদি তারপর চেষ্টা করি এবং সম্পত্তিগুলির সেটিংটি এর মতো করে একত্র করি:

public string MyProperty
{
    set
    {
        if (_myProperty != value)
        {
            _myProperty = value;
            NotifyPropertyChanged("MyProperty");
            MyOtherProperty = "SomeValue";
        }
    }
}

public string MyOtherProperty
{
    set
    {
        if (_myOtherProperty != value)
        {
            _myOtherProperty = value;
            NotifyPropertyChanged("MyOtherProperty");
        }
    }
}

ইভেন্টটির জন্য আমার পরীক্ষা ব্যর্থ হয় - এটি যে ইভেন্টটি ধারণ করে তা হ'ল মওথারপ্রপারটির ইভেন্ট।

আমি নিশ্চিত যে ঘটনাটি আগুনে ছড়িয়ে পড়ে, আমার ইউআই এর মতো প্রতিক্রিয়া দেখায় তবে আমার প্রতিনিধি কেবল শেষ ঘটনাটি আগুনে ধরতে পারে।

সুতরাং আমি ভাবছি:
১. ঘটনাগুলি পরীক্ষার আমার পদ্ধতি কি সঠিক?
২. আমার শৃঙ্খলাবদ্ধ ঘটনা উত্থাপনের পদ্ধতি কি সঠিক?

উত্তর:


190

আপনি যা করেছেন তা সবই সঠিক, আপনার পরীক্ষাটি জিজ্ঞাসা করতে চাইলে "উত্থাপিত শেষ ঘটনাটি কী?"

আপনার কোডটি এই ক্রমে এই দুটি ইভেন্ট ফায়ার করছে

  • সম্পত্তি পরিবর্তিত (... "আমার সম্পত্তি" ...)
  • সম্পত্তি পরিবর্তন করা হয়েছে (... "আমারঅর্থপ্রটি" ...)

এটি "সঠিক" কিনা তা এই ইভেন্টগুলির উদ্দেশ্যটির উপর নির্ভর করে।

আপনি যদি উত্থাপিত ইভেন্টগুলির সংখ্যা এবং সেগুলি যেভাবে উত্থাপিত হয় সেগুলি পরীক্ষা করতে চান, আপনি সহজেই আপনার বিদ্যমান পরীক্ষাটি বাড়িয়ে দিতে পারেন:

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    List<string> receivedEvents = new List<string>();
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
        receivedEvents.Add(e.PropertyName);
    };

    myClass.MyProperty = "testing";
    Assert.AreEqual(2, receivedEvents.Count);
    Assert.AreEqual("MyProperty", receivedEvents[0]);
    Assert.AreEqual("MyOtherProperty", receivedEvents[1]);
}

13
সংক্ষিপ্ত সংস্করণ: myClass.PropertyChanged + = (অবজেক্ট প্রেরক, ই) => প্রাপ্তEvents.Add (e.PropertyName);
ShloEmi

22

আপনি যদি টিডিডি করছেন তবে ইভেন্ট টেস্টিং প্রচুর পুনরাবৃত্তি কোড উত্পন্ন করা শুরু করতে পারে । আমি একটি ইভেন্ট মনিটর লিখেছি যা এই পরিস্থিতিতে ইউনিট পরীক্ষার লেখার ক্ষেত্রে আরও পরিচ্ছন্ন পদ্ধতির সক্ষম করে।

var publisher = new PropertyChangedEventPublisher();

Action test = () =>
{
    publisher.X = 1;
    publisher.Y = 2;
};

var expectedSequence = new[] { "X", "Y" };

EventMonitor.Assert(test, publisher, expectedSequence);

আরও তথ্যের জন্য দয়া করে নীচের আমার উত্তরটি দেখুন।

প্রতিচ্ছবি ব্যবহার করে একটি ইভেন্ট সি # তে উত্থাপিত হয়েছে এমন ইউনিট পরীক্ষণ


3
দ্বিতীয় লিঙ্ক ডাউন।
লেনার্ট

10

এটি খুব পুরানো এবং সম্ভবত পড়াও হবে না তবে কিছু দুর্দান্ত নতুন নেট বৈশিষ্ট্য সহ আমি একটি আইএনপিসি ট্রেসার ক্লাস তৈরি করেছি যা এটির অনুমতি দেয়:

[Test]
public void Test_Notify_Property_Changed_Fired()
{
    var p = new Project();

    var tracer = new INCPTracer();

    // One event
    tracer.With(p).CheckThat(() => p.Active = true).RaisedEvent(() => p.Active);

    // Two events in exact order
    tracer.With(p).CheckThat(() => p.Path = "test").RaisedEvent(() => p.Path).RaisedEvent(() => p.Active);
}

গিস্টটি দেখুন: https://gist.github.com/Seikigs/6224204


সুন্দর - আপনার এটি প্যাকেজিং এবং nuget.org এ প্রকাশের কথা বিবেচনা করা উচিত
সাইমন এজেজিং

1
মহান কাজ! আমি সত্যিই সাবলীল এপিআই খনন করি। আমি নিজেই অনুরূপ কিছু করেছি ( github.com/f-tischler/EventTesting ) তবে আমি মনে করি আপনার পদ্ধতির আরও সংক্ষিপ্ত।
ফ্লোরিয়ান টিশলার

6

নীচে একটি সামান্য পরিবর্তিত অ্যান্ড্রু কোড দেওয়া হয়েছে যা উত্থাপিত ইভেন্টগুলির ক্রমটি কেবল লগ করার পরিবর্তে নির্দিষ্ট ইভেন্টকে ডাকা হয়েছে বলে গণনা করেছে। যদিও এটি তার কোডের উপর ভিত্তি করে আমি আমার পরীক্ষাগুলিতে এটি আরও দরকারী বলে মনে করি।

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    Dictionary<string, int> receivedEvents = new Dictionary<string, int>();
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
        if (receivedEvents.ContainsKey(e.PropertyName))
            receivedEvents[e.PropertyName]++;
        else
            receivedEvents.Add(e.PropertyName, 1);
    };

    myClass.MyProperty = "testing";
    Assert.IsTrue(receivedEvents.ContainsKey("MyProperty"));
    Assert.AreEqual(1, receivedEvents["MyProperty"]);
    Assert.IsTrue(receivedEvents.ContainsKey("MyOtherProperty"));
    Assert.AreEqual(1, receivedEvents["MyOtherProperty"]);
}

1

এই নিবন্ধের উপর ভিত্তি করে, আমি এই সাধারণ দৃ help় সহায়ক সহায়ক তৈরি করেছি:

private void AssertPropertyChanged<T>(T instance, Action<T> actionPropertySetter, string expectedPropertyName) where T : INotifyPropertyChanged
    {
        string actual = null;
        instance.PropertyChanged += delegate (object sender, PropertyChangedEventArgs e)
        {
            actual = e.PropertyName;
        };
        actionPropertySetter.Invoke(instance);
        Assert.IsNotNull(actual);
        Assert.AreEqual(propertyName, actual);
    }

এই পদ্ধতির সহায়তার সাথে, পরীক্ষাটি সত্যই সহজ হয়ে যায়।

[TestMethod()]
public void Event_UserName_PropertyChangedWillBeFired()
{
    var user = new User();
    AssertPropertyChanged(user, (x) => x.UserName = "Bob", "UserName");
}

1

প্রতিটি সদস্যের জন্য একটি পরীক্ষা লিখবেন না - এটি অনেক কাজ

(সম্ভবত এই সমাধানটি প্রতিটি পরিস্থিতির জন্য উপযুক্ত নয় - তবে এটি একটি সম্ভাব্য উপায় দেখায় your আপনার ব্যবহারের ক্ষেত্রে এটি আপনাকে খাপ খাইয়ে নিতে হতে পারে)

আপনার সদস্যরা সকলেই আপনার সম্পত্তি পরিবর্তিত ইভেন্টটিকে সঠিকভাবে প্রতিক্রিয়া জানাচ্ছেন কিনা তা পরীক্ষা করার জন্য একটি লাইব্রেরিতে প্রতিবিম্ব ব্যবহার করা সম্ভব:

  • প্রপার্টি চেঞ্জড ইভেন্টটি সেটার অ্যাক্সেসে উত্থাপিত হয়
  • ইভেন্টটি সঠিকভাবে উত্থাপিত হয়েছে (সম্পত্তির নাম উত্থাপিত ইভেন্টের যুক্তির সমতুল্য)

নিম্নলিখিত কোডটি একটি লাইব্রেরি হিসাবে ব্যবহার করা যেতে পারে এবং নিম্নলিখিত জেনেরিক ক্লাসটি পরীক্ষা করার পদ্ধতিটি দেখায়

using System.ComponentModel;
using System.Linq;

/// <summary>
/// Check if every property respons to INotifyPropertyChanged with the correct property name
/// </summary>
public static class NotificationTester
    {
        public static object GetPropertyValue(object src, string propName)
        {
            return src.GetType().GetProperty(propName).GetValue(src, null);
        }

        public static bool Verify<T>(T inputClass) where T : INotifyPropertyChanged
        {
            var properties = inputClass.GetType().GetProperties().Where(x => x.CanWrite);
            var index = 0;

            var matchedName = 0;
            inputClass.PropertyChanged += (o, e) =>
            {
                if (properties.ElementAt(index).Name == e.PropertyName)
                {
                    matchedName++;
                }

                index++;
            };

            foreach (var item in properties)
            { 
                // use setter of property
                item.SetValue(inputClass, GetPropertyValue(inputClass, item.Name));
            }

            return matchedName == properties.Count();
        }
    }

আপনার ক্লাসের পরীক্ষাগুলি এখন লিখতে পারেন। (সম্ভবত আপনি পরীক্ষাকে "ইভেন্টটি আছে" এবং "সঠিক নাম দিয়ে উত্থাপিত ইভেন্ট" - এ ভাগ করতে চান - আপনি নিজে এটি করতে পারেন)

[TestMethod]
public void EveryWriteablePropertyImplementsINotifyPropertyChangedCorrect()
{
    var viewModel = new TestMyClassWithINotifyPropertyChangedInterface();
    Assert.AreEqual(true, NotificationTester.Verify(viewModel));
}

শ্রেণী

using System.ComponentModel;

public class TestMyClassWithINotifyPropertyChangedInterface : INotifyPropertyChanged
{
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        private int id;

        public int Id
        {
            get { return id; }
            set { id = value;
                NotifyPropertyChanged("Id");
            }
        }
}

আমি এটি চেষ্টা করেছি, তবে যদি আমার সম্পত্তি সেটারের কাছে যদি "যদি (মান == _ মাইভ্যালু) রিটার্ন" এর মত গার্ড স্টেটমেন্ট থাকে যা আমার সমস্ত কাজ করে তবে উপরের কাজ করবে না, যতক্ষণ না আমি কিছু মিস করছি। আমি সম্প্রতি সি ++ থেকে সি # এ এসেছি।
কোডাহ 21

0

আমি এখানে একটি এক্সটেনশন করেছি:

public static class NotifyPropertyChangedExtensions
{
    private static bool _isFired = false;
    private static string _propertyName;

    public static void NotifyPropertyChangedVerificationSettingUp(this INotifyPropertyChanged notifyPropertyChanged,
      string propertyName)
    {
        _isFired = false;
        _propertyName = propertyName;
        notifyPropertyChanged.PropertyChanged += OnPropertyChanged;
    }

    private static void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == _propertyName)
        {
            _isFired = true;
        }
    }

    public static bool IsNotifyPropertyChangedFired(this INotifyPropertyChanged notifyPropertyChanged)
    {
        _propertyName = null;
        notifyPropertyChanged.PropertyChanged -= OnPropertyChanged;
        return _isFired;
    }
}

ব্যবহার আছে:

   [Fact]
    public void FilesRenameViewModel_Rename_Apply_Execute_Verify_NotifyPropertyChanged_If_Succeeded_Through_Extension_Test()
    {
        //  Arrange
        _filesViewModel.FolderPath = ConstFolderFakeName;
        _filesViewModel.OldNameToReplace = "Testing";
        //After the command's execution OnPropertyChanged for _filesViewModel.AllFilesFiltered should be raised
        _filesViewModel.NotifyPropertyChangedVerificationSettingUp(nameof(_filesViewModel.AllFilesFiltered));
        //Act
        _filesViewModel.ApplyRenamingCommand.Execute(null);
        // Assert
        Assert.True(_filesViewModel.IsNotifyPropertyChangedFired());

    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.