ইউনিট টেস্টিং: ডেটটাইম.এখন


164

আমার কিছু ইউনিট পরীক্ষা আছে যা প্রত্যাশা করে যে 'বর্তমান সময়' ডেটটাইমের চেয়ে আলাদা হবে ow এখন এবং আমি অবশ্যই কম্পিউটারের সময় পরিবর্তন করতে চাই না obvious

এটি অর্জনের সেরা কৌশল কী?


বর্তমান সময়ে কিছু পুরানো মান সংরক্ষণ করুন এবং এটি ডেটটাইম.এর সাথে তুলনা করুন, ইউনিট টেস্টিং নকল ডেটা ব্যবহার করে, আপনি সহজেই তা করতে পারেন, তাই না?
প্রশান্ত লখলানী

3
বর্তমান ডেটটাইমের বিমূর্ততা সরবরাহ করা কেবল টেস্টিং এবং ডিবাগিংয়ের জন্যই নয় তবে উত্পাদন কোডেও কার্যকর - এটি অ্যাপ্লিকেশন প্রয়োজনীয়তার উপর নির্ভর করে।
পাভেল হোডেক

1
ডেটটাইম পেতে স্ট্যাটিক ক্লাস ব্যবহার করবেন না
ড্যানিয়েল লিটল

এবং নীচে ভার্চুয়ালটাইম ব্যবহার করে অন্য একটি সহজ পদ্ধতি
স্যামুয়েল

একটি বিকল্প যা কাজ করতে পারে এবং আপনি একটি ওভারলোড যুক্ত করতে সক্ষম হবেন সেটি এমন পদ্ধতির একটি ওভারলোড তৈরি করা যা গ্রহণ করে DateTime। এটিই আপনি যা পরীক্ষা করেন এটি বিদ্যমান পদ্ধতিটি কেবল ওভারলোডকে কল করে now
ফিল কুপার

উত্তর:


218

সেরা কৌশল হয় বিমূর্ততা বর্তমান সময় মোড়ানো এবং ক্রেতার মধ্যে যে বিমূর্ততা উদ্বুদ্ধ


বিকল্পভাবে , আপনি একটি সময় বিমূর্তিটিকে একটি অ্যাম্বিয়েন্ট প্রসঙ্গ হিসাবেও সংজ্ঞায়িত করতে পারেন :

public abstract class TimeProvider
{
    private static TimeProvider current =
        DefaultTimeProvider.Instance;

    public static TimeProvider Current
    {
       get { return TimeProvider.current; }
       set 
       {
           if (value == null)
           {
               throw new ArgumentNullException("value");
           }
           TimeProvider.current = value; 
       }
   }

   public abstract DateTime UtcNow { get; }

   public static void ResetToDefault()
   {    
       TimeProvider.current = DefaultTimeProvider.Instance;
   }            
}

এটি আপনাকে এটির মতো গ্রাস করতে সক্ষম করবে:

var now = TimeProvider.Current.UtcNow;

ইউনিট পরীক্ষায়, আপনি TimeProvider.Currentএকটি পরীক্ষা ডাবল / মক অবজেক্টের সাথে প্রতিস্থাপন করতে পারেন । মোক ব্যবহারের উদাহরণ:

var timeMock = new Mock<TimeProvider>();
timeMock.SetupGet(tp => tp.UtcNow).Returns(new DateTime(2010, 3, 11));
TimeProvider.Current = timeMock.Object;

যাইহোক, যখন স্ট্যাটিক রাষ্ট্র নিয়ে পরীক্ষা ইউনিট, সবসময় মনে রাখবেন আপনার চোকান চূর্ণ করা কল করে TimeProvider.ResetToDefault()


7
একটি পরিবেষ্টনের প্রসঙ্গে, আপনি ছিঁড়ে ফেললেও, কীভাবে আপনি আপনার পরীক্ষাগুলিকে সমান্তরালভাবে চালিত করবেন?
ইলিয়া চেরনমর্ডিক

2
@ ইলিয়াচেরনমর্ডিক আপনার আইলোগার বা অন্যান্য ক্রস কাটিং কনসার্নস ইনজেক্ট করা উচিত নয় , তাই সময় সরবরাহকারী ইনজেকশন করা এখনও সেরা বিকল্প।
মার্ক সিমেন

5
@ মাইক আমার উত্তরটির প্রথম বাক্য হিসাবে বলেছে: বর্তমান কৌশলটি একটি বিমূর্ততায় আবৃত করা এবং সেই বিমূর্ততাটি গ্রাহকের মধ্যে ইনজেকশনের সেরা কৌশল strategy এই উত্তরের সমস্ত কিছুই দ্বিতীয়-সেরা বিকল্প।
মার্ক সিমেন

3
ওহে. আমি নুব। কীভাবে কেউ এই সমাধানের সাহায্যে লোককে ডেটটাইম অ্যাক্সেস করতে বাধা দেয়? টাইমপ্রাইডার ব্যবহার করে কারও পক্ষে মিস করা সহজ হবে be এভাবে পরীক্ষায় বাগ বাড়ে?
আবেগ প্রকাশ করুন

1
@ ওবলস কোড পর্যালোচনা (বা জুড়ি প্রোগ্রামিং, যা লাইভ কোড পর্যালোচনার একটি ফর্ম)। আমি মনে করি যে কেউ এমন একটি সরঞ্জাম লিখতে পারে যা কোড বেসটি DateTime.UtcNowএবং এর অনুরূপ স্ক্যান করে তবে কোড পর্যালোচনা যাইহোক ভাল ধারণা।
মার্ক সিমেন

58

এগুলি সব ভাল উত্তর, আমি ভিন্ন প্রকল্পে এটি করেছি:

ব্যবহার:

আজকের বাস্তব তারিখের সময়টি পান

var today = SystemTime.Now().Date;

ডেটটাইম.নাউ ব্যবহার করার পরিবর্তে, আপনার ব্যবহার করা দরকার SystemTime.Now()... এটি কঠোর পরিবর্তন নয় তবে এই সমাধানটি সমস্ত প্রকল্পের জন্য আদর্শ নাও হতে পারে।

সময় ভ্রমণ (ভবিষ্যতে 5 বছর যেতে দেয়)

SystemTime.SetDateTime(today.AddYears(5));

আমাদের জাল "আজ" পান ('আজ' থেকে 5 বছর হবে)

var fakeToday = SystemTime.Now().Date;

তারিখটি পুনরায় সেট করুন

SystemTime.ResetDateTime();

/// <summary>
/// Used for getting DateTime.Now(), time is changeable for unit testing
/// </summary>
public static class SystemTime
{
    /// <summary> Normally this is a pass-through to DateTime.Now, but it can be overridden with SetDateTime( .. ) for testing or debugging.
    /// </summary>
    public static Func<DateTime> Now = () => DateTime.Now;

    /// <summary> Set time to return when SystemTime.Now() is called.
    /// </summary>
    public static void SetDateTime(DateTime dateTimeNow)
    {
        Now = () =>  dateTimeNow;
    }

    /// <summary> Resets SystemTime.Now() to return DateTime.Now.
    /// </summary>
    public static void ResetDateTime()
    {
        Now = () => DateTime.Now;
    }
}

1
আপনাকে ধন্যবাদ, আমি এই কার্যকরী aproach পছন্দ। আজ (দু'বছর পরে) আমি এখনও টাইমপ্রাইডার শ্রেণীর একটি পরিবর্তিত সংস্করণ ব্যবহার করছি (গৃহীত উত্তরটি পরীক্ষা করুন), এটি সত্যিই দুর্দান্ত কাজ করে।
পেড্রো

7
@crabCRUSHERclamCOLI: আপনার কাছ থেকে ধারণা পেয়েছেন এমন ayende.com/blog/3408/dealing-with-time-in-tests , তাহলে এটি একটি ভাল জিনিস এটা লিঙ্ক আছে।
জোহান জেরেল

3
; এই ধারণা আরো উপহাস GUID প্রজন্ম (পাবলিক স্ট্যাটিক Func <GUID> NewGuid = () => Guid.NewGuid () জন্য কাজ করে মহান
mdwhatcott

2
আপনি এই দরকারী পদ্ধতিটিও যুক্ত করতে পারেন: পাবলিক স্ট্যাটিক শূন্যতা রিসেটডেটটাইম (তারিখের সময়সীমার সময়) এখন = () => তারিখের সময়.এখন - টাইমস্প্যানডিফ; }
পাভেল হোদেক

17
খুব বিপজ্জনক his এটি সমান্তরালে চলমান অন্যান্য ইউনিট পরীক্ষাগুলিকে প্রভাবিত করতে পারে।
এমেটে ধন্য মঙ্গল

24

মাপ:

[Test]  
public void TestOfDateTime()  
{  
      var firstValue = DateTime.Now;
      MDateTime.NowGet = () => new DateTime(2000,1,1);
      var secondValue = DateTime.Now;
      Assert(firstValue > secondValue); // would be false if 'moleing' failed
}

দাবি অস্বীকার - আমি মোলসে কাজ করি


1
দুর্ভাগ্যক্রমে নুনিট এবং পুনরায় ভাগ করা নিয়ে কাজ করে না।
অষ্টম

দেখে মনে হচ্ছে যে মোলস এখন অসমর্থিত, ফেকস এমএসডিএন.মাইক্রোসফটকম / en- us / library/… দিয়ে প্রতিস্থাপিত হয়েছে , সন্দেহ নেই এমএস খুব তাড়াতাড়ি বন্ধ করে দেবে
ড্যানিও

17

এটি করার জন্য আপনার কাছে কিছু বিকল্প রয়েছে:

  1. উপহাসের কাঠামোটি ব্যবহার করুন এবং একটি ডেটটাইমসেসওয়ারি ব্যবহার করুন (একটি ছোট র‌্যাপার ক্লাস প্রয়োগ করুন এবং এটি উত্পাদন কোডে ইনজেকশন করুন)। মোড়কের বাস্তবায়ন ডেটটাইম অ্যাক্সেস করবে এবং পরীক্ষাগুলিতে আপনি মোড়কের ক্লাসকে উপহাস করতে সক্ষম হবেন।

  2. টাইপমক আইসোলেটর ব্যবহার করুন , এটি ডেটটাইমকে নকল করতে পারে owএখন আপনাকে পরীক্ষার অধীনে কোডটি পরিবর্তন করতে হবে না।

  3. মোলস ব্যবহার করুন , এটি ডেটটাইমও নকল করতে পারে ow এখন এবং উত্পাদন কোডে কোনও পরিবর্তন প্রয়োজন হবে না।

কিছু উদাহরণ:

মোকার ব্যবহার করে মোড়কের ক্লাস:

[Test]
public void TestOfDateTime()
{
     var mock = new Mock<IDateTime>();
     mock.Setup(fake => fake.Now)
         .Returns(new DateTime(2000, 1, 1));

     var result = new UnderTest(mock.Object).CalculateSomethingBasedOnDate();
}

public class DateTimeWrapper : IDateTime
{
      public DateTime Now { get { return DateTime.Now; } }
}

সরাসরি আইসোলেটর ব্যবহার করে ডেটটাইম ফেকিং:

[Test]
public void TestOfDateTime()
{
     Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2000, 1, 1));

     var result = new UnderTest().CalculateSomethingBasedOnDate();
}

দাবি অস্বীকার - আমি টাইপমক এ কাজ করি


12

সিস্টেমের জন্য একটি নকল সমাবেশ যুক্ত করুন (সিস্টেমের রেফারেন্সে ডান ক্লিক করুন => জাল সমাবেশ যোগ করুন)।

এবং আপনার পরীক্ষা পদ্ধতিতে লিখুন:

using (ShimsContext.Create())
{
   System.Fakes.ShimDateTime.NowGet = () => new DateTime(2014, 3, 10);
   MethodThatUsesDateTimeNow();
}

যদি আপনার ভিএস প্রিমিয়াম বা চূড়ান্ত অ্যাক্সেস থাকে তবে এটি করা এখন পর্যন্ত সবচেয়ে সহজ / দ্রুততম উপায়।
রাগদর

7

@ ক্র্যাবক্রাশারক্ল্যামক্লাক্টর উত্তর সম্পর্কে ইএফ ক্যোয়ারিতে এই পদ্ধতির ব্যবহার করার সময় সমস্যা আছে (সিস্টেম.নোটসপোর্টেড এক্সপশন: লিনকু এক্সপ্রেশন নোড টাইপ 'ইনভোক' লিনকু টু সত্তায় সমর্থিত নয়)। আমি এতে বাস্তবায়নটি পরিবর্তন করেছি:

public static class SystemTime
    {
        private static Func<DateTime> UtcNowFunc = () => DateTime.UtcNow;

        public static void SetDateTime(DateTime dateTimeNow)
        {
            UtcNowFunc = () => dateTimeNow;
        }

        public static void ResetDateTime()
        {
            UtcNowFunc = () => DateTime.UtcNow;
        }

        public static DateTime UtcNow
        {
            get
            {
                DateTime now = UtcNowFunc.Invoke();
                return now;
            }
        }
    }

আমি ইএফ দ্বারা অনুমান করছি আপনি সত্তা ফ্রেমওয়ার্ক মানে? আপনি সিস্টেমটাইমটি দেখতে কীভাবে অবজেক্টটি ব্যবহার করছেন? আমার অনুমান যে আপনার প্রকৃত সত্তায় সিস্টেমটাইমের একটি রেফারেন্স রয়েছে, পরিবর্তে আপনার নিজের সত্তায় নিয়মিত ডেটটাইম অবজেক্টটি ব্যবহার করা উচিত এবং আপনার অ্যাপ্লিকেশনটিতে যেখানেই এটি উপলব্ধি করা যায় সেখানে
সিস্টেমটাইম

1
হ্যাঁ আমি লিনক ক্যোয়ারী এবং সত্তা ফ্রেমওয়ার্ক 6 তৈরি করার সময় এবং সিস্টেম টাইম থেকে উটউনোকে সেই ক্যোয়ারিতে রেফারেন্স করার সময় এটি পরীক্ষা করেছি। বর্ণিত হিসাবে ব্যতিক্রম ছিল। বাস্তবায়ন পরিবর্তনের পরে এটি ভালভাবে কাজ করে।
মার্সিন

আমি এই সমাধান ভালোবাসি! গ্রেট!
মিরিন্ড 4

7

, এর উপর নির্ভর করে এমন একটি কোড পরীক্ষা System.DateTimeকরতেsystem.dll অবশ্যই বিদ্রূপ করা উচিত।

আমি জানি যে দুটি কাঠামো এটি করে। মাইক্রোসফ্ট জালিয়াতি এবং স্মোকস

মাইক্রোসফ্ট ফেকসের জন্য ভিজ্যুয়াল স্টুডিও 2012 এর আলটিমেটাম প্রয়োজন এবং সরাসরি বেতার বাইরে কাজ করে।

স্মোকস একটি উন্মুক্ত উত্স এবং ব্যবহার করা খুব সহজ। এটি নুগেট ব্যবহার করে ডাউনলোড করা যায়।

নিম্নলিখিত একটি উপহাস দেখায় System.DateTime:

Smock.Run(context =>
{
  context.Setup(() => DateTime.Now).Returns(new DateTime(2000, 1, 1));

   // Outputs "2000"
   Console.WriteLine(DateTime.Now.Year);
});

5

একটি থ্রেড SystemClockব্যবহার নিরাপদ ThreadLocal<T>আমার জন্য দুর্দান্ত কাজ করে ।

ThreadLocal<T> .NET ফ্রেমওয়ার্ক v4.0 এবং উচ্চতরতে উপলব্ধ।

/// <summary>
/// Provides access to system time while allowing it to be set to a fixed <see cref="DateTime"/> value.
/// </summary>
/// <remarks>
/// This class is thread safe.
/// </remarks>
public static class SystemClock
{
    private static readonly ThreadLocal<Func<DateTime>> _getTime =
        new ThreadLocal<Func<DateTime>>(() => () => DateTime.Now);

    /// <inheritdoc cref="DateTime.Today"/>
    public static DateTime Today
    {
        get { return _getTime.Value().Date; }
    }

    /// <inheritdoc cref="DateTime.Now"/>
    public static DateTime Now
    {
        get { return _getTime.Value(); }
    }

    /// <inheritdoc cref="DateTime.UtcNow"/>
    public static DateTime UtcNow
    {
        get { return _getTime.Value().ToUniversalTime(); }
    }

    /// <summary>
    /// Sets a fixed (deterministic) time for the current thread to return by <see cref="SystemClock"/>.
    /// </summary>
    public static void Set(DateTime time)
    {
        if (time.Kind != DateTimeKind.Local)
            time = time.ToLocalTime();

        _getTime.Value = () => time;
    }

    /// <summary>
    /// Resets <see cref="SystemClock"/> to return the current <see cref="DateTime.Now"/>.
    /// </summary>
    public static void Reset()
    {
        _getTime.Value = () => DateTime.Now;
    }
}

ব্যবহারের উদাহরণ:

[TestMethod]
public void Today()
{
    SystemClock.Set(new DateTime(2015, 4, 3));

    DateTime expectedDay = new DateTime(2015, 4, 2);
    DateTime yesterday = SystemClock.Today.AddDays(-1D);
    Assert.AreEqual(expectedDay, yesterday);

    SystemClock.Reset();
}

1
+ +! থ্রেড স্থানীয়কে সমান্তরাল পরীক্ষার সম্পাদনা এবং একাধিক পরীক্ষার সম্ভাব্য বর্তমান Nowদৃষ্টিতে ওভাররাইড করার সমস্যাগুলি এড়ানো উচিত ।
হাক্স

1
এটি ব্যবহারের চেষ্টা করা হলেও থ্রেড জুড়ে একটি সমস্যা ছিল তাই একই রকম প্রিন্সিপালের সাথে গিয়েছে তবে ব্যবহার AsyncLocalকরার পরিবর্তেThreadLocal
rrrr

@ আরআরআর: আপনার যে সমস্যাটি ছিল তা কি আপনি ব্যাখ্যা করতে পারেন?
হেন্ক ভ্যান বোয়েজেন

@ হেনকভানবোইজেন অবশ্যই, সময় নির্ধারিত হওয়ার পরে আমরা সমস্যাগুলির মধ্যে ছড়িয়ে পড়েছিলাম এবং তখন আমরা একটি অ্যাসিঙ্ক পদ্ধতির অপেক্ষায় ছিলাম। Console.WriteLine(SystemClock.Now); SystemClock.Set(new DateTime(2017, 01, 01)); Console.WriteLine(SystemClock.Now); await Task.Delay(1000); Console.WriteLine(SystemClock.Now);
rrrr

@ হেনকানবোইজেন আমি লিঙ্কটি
rrrr

3

আমি এই একই ইস্যুতে দৌড়েছি তবে মাইক্রোসফ্ট থেকে একটি গবেষণা প্রকল্প পেয়েছি যা এই সমস্যাটি সমাধান করে।

http://research.microsoft.com/en-us/projects/moles/

মোলগুলি পরীক্ষার স্টাবগুলি এবং .NET- র চার্চের জন্য একটি হালকা ফ্রেমওয়ার্ক যা প্রতিনিধিদের উপর ভিত্তি করে তৈরি হয়। সিলযুক্ত ধরণের অ-ভার্চুয়াল / স্ট্যাটিক পদ্ধতি সহ কোনও NET পদ্ধতি ডিফলের জন্য মোল ব্যবহার করা যেতে পারে

// Let's detour DateTime.Now
MDateTime.NowGet = () => new DateTime(2000,1, 1);

if (DateTime.Now == new DateTime(2000, 1, 1);
{
    throw new Exception("Wahoo we did it!");
}

নমুনা কোডটি মূল থেকে পরিবর্তন করা হয়েছিল।

অন্যরা যা প্রস্তাব করেছিল এবং ডেটটাইমকে সরবরাহকারী হিসাবে বিমূর্ত করেছিল তা আমি করেছিলাম। এটি ঠিক ভুল অনুভব করেছে এবং আমার মনে হয়েছে এটি কেবল পরীক্ষার জন্য খুব বেশি was আমি এই সন্ধ্যায় আমার ব্যক্তিগত প্রকল্পে এটি বাস্তবায়ন করতে যাচ্ছি।


2
বিটিডাব্লু, এটি কেবল ভিএস 2010 দিয়ে কাজ করে। যখন আমি জানতে পারি যে মোলস এখন ভিএস ২০১২ এর জন্য নকল এবং এটি কেবল প্রিমিয়াম এবং আলটিমেট ভিজ্যুয়াল স্টুডিওগুলির জন্য উপলব্ধ। ভিএস 2012 পেশাদারের জন্য কোনও জাল নেই। সুতরাং আমি কখনই বাস্তবে এটি ব্যবহার করতে পারি নি। :(
ববি ক্যানন

3

টাইপমকেরDateTime.Now সাথে ঠাট্টা করার বিষয়ে একটি বিশেষ নোট ...

DateTime.Nowএটিকে সঠিকভাবে উপহাস করার জন্য মানটির অবশ্যই পরিবর্তনশীলতে রাখতে হবে। উদাহরণ স্বরূপ:

এটা কাজ করে না:

if ((DateTime.Now - message.TimeOpened.Value) > new TimeSpan(1, 0, 0))

তবে এটি করে:

var currentDateTime = DateTime.Now;
if ((currentDateTime - message.TimeOpened.Value) > new TimeSpan(1, 0, 0))

2

মক অবজেক্টস।

একটি মক ডেটটাইম যা আপনার পরীক্ষার জন্য উপযুক্ত এটি এখন ফেরত দেয়।


2

আমি অবাক হয়েছি কেউ যাওয়ার সবচেয়ে সুস্পষ্ট উপায়ের কোনও প্রস্তাব দেয়নি:

public class TimeDependentClass
{
    public void TimeDependentMethod(DateTime someTime)
    {
        if (GetCurrentTime() > someTime) DoSomething();
    }

    protected virtual DateTime GetCurrentTime()
    {
        return DateTime.Now; // or UtcNow
    }
}

তারপরে আপনি কেবল আপনার পরীক্ষার দ্বিগুণে এই পদ্ধতিটিকে ওভাররাইড করতে পারেন।

আমি TimeProviderকিছু ক্ষেত্রে ক্লাসে ইনজেকশন দেওয়ার মতোও করি , তবে অন্যদের জন্য এটি যথেষ্ট পরিমাণে বেশি। TimeProviderযদিও আপনাকে বেশ কয়েকটি ক্লাসে এটি পুনরায় ব্যবহার করতে হবে তবে আমি সম্ভবত সংস্করণটির পক্ষে চাই ।

সম্পাদনা: আগ্রহী প্রত্যেকের জন্য, এটি আপনার ক্লাসে "সিম" যুক্ত বলা হয়, এমন একটি বিন্দু যেখানে আপনি ক্লাসে কোডটি পরিবর্তন না করেই এটির পরিবর্তনের (পরীক্ষার উদ্দেশ্যে বা অন্যথায়) এটির আচরণের দিকে ঝুঁকতে পারেন।


1

ভাল অনুশীলন হয়, যখন ডেটটাইমপ্রোভাইডার আইডিপোজেবল কার্যকর করে।

public class DateTimeProvider : IDisposable 
{ 
    [ThreadStatic] 
    private static DateTime? _injectedDateTime; 

    private DateTimeProvider() 
    { 
    } 

    /// <summary> 
    /// Gets DateTime now. 
    /// </summary> 
    /// <value> 
    /// The DateTime now. 
    /// </value> 
    public static DateTime Now 
    { 
        get 
        { 
            return _injectedDateTime ?? DateTime.Now; 
        } 
    } 

    /// <summary> 
    /// Injects the actual date time. 
    /// </summary> 
    /// <param name="actualDateTime">The actual date time.</param> 
    public static IDisposable InjectActualDateTime(DateTime actualDateTime) 
    { 
        _injectedDateTime = actualDateTime; 

        return new DateTimeProvider(); 
    } 

    public void Dispose() 
    { 
        _injectedDateTime = null; 
    } 
} 

এর পরে, আপনি ইউনিট পরীক্ষার জন্য আপনার জাল ডেটটাইম ইনজেকশন করতে পারেন

    using (var date = DateTimeProvider.InjectActualDateTime(expectedDateTime)) 
    { 
        var bankAccount = new BankAccount(); 

        bankAccount.DepositMoney(600); 

        var lastTransaction = bankAccount.Transactions.Last(); 

        Assert.IsTrue(expectedDateTime.Equals(bankAccount.Transactions[0].TransactionDate)); 
    } 

তারিখটাইমপ্রভাইডারের উদাহরণ দেখুন


1

এটি করার একটি পরিষ্কার উপায় ভার্চুয়ালটাইম ইনজেকশন। এটি আপনাকে সময় নিয়ন্ত্রণ করতে দেয়। প্রথমে ভার্চুয়ালটাইম ইনস্টল করুন

Install-Package VirtualTime

এটি উদাহরণস্বরূপ, এমন সময় তৈরি করতে দেয় যা সমস্ত কলগুলিতে ডেটটাইম-এ 5 বার দ্রুত চলে moves এখন বা উত্কনউ

var DateTime = DateTime.Now.ToVirtualTime(5);

সময়কে ধীরে ধীরে চালিত করতে, যেমন 5 বার ধীর করুন

var DateTime = DateTime.Now.ToVirtualTime(0.5);

সময় স্থির করতে এখনও করতে

var DateTime = DateTime.Now.ToVirtualTime(0);

সময়ে পিছনে সরানো এখনও পরীক্ষা করা হয় না

এখানে একটি নমুনা পরীক্ষা দেওয়া হচ্ছে:

[TestMethod]
public void it_should_make_time_move_faster()
{
    int speedOfTimePerMs = 1000;
    int timeToPassMs = 3000;
    int expectedElapsedVirtualTime = speedOfTimePerMs * timeToPassMs;
    DateTime whenTimeStarts = DateTime.Now;
    ITime time = whenTimeStarts.ToVirtualTime(speedOfTimePerMs);
    Thread.Sleep(timeToPassMs);
    DateTime expectedTime = DateTime.Now.AddMilliseconds(expectedElapsedVirtualTime - timeToPassMs);
    DateTime virtualTime = time.Now;

    Assert.IsTrue(TestHelper.AreEqualWithinMarginOfError(expectedTime, virtualTime, MarginOfErrorMs));
}

আপনি আরও পরীক্ষা এখানে পরীক্ষা করতে পারেন:

https://github.com/VirtualTime/VirtualTime/blob/master/VirtualTimeLib.Tests/when_virtual_time_is_used.cs

ডেটটাইম.নিউ. টু ভার্চুয়ালটাইম এক্সটেনশন আপনাকে আইটিটাইমের একটি উদাহরণ দেয় যা আপনি কোনও পদ্ধতি / শ্রেণিতে পাস করেন যা আইটিমে উপর নির্ভর করে। কিছু ডেটটাইম.নিউ. টু ভার্চুয়ালটাইম আপনার পছন্দের ডিআই কনটেইনারে সেটআপ রয়েছে

এখানে ক্লাস কনট্রাস্টার ইনজেকশনের আরও একটি উদাহরণ

public class AlarmClock
{
    private ITime DateTime;
    public AlarmClock(ITime dateTime, int numberOfHours)
    {
        DateTime = dateTime;
        SetTime = DateTime.UtcNow.AddHours(numberOfHours);
        Task.Run(() =>
        {
            while (!IsAlarmOn)
            {
                IsAlarmOn = (SetTime - DateTime.UtcNow).TotalMilliseconds < 0;
            }
        });
    }
    public DateTime SetTime { get; set; }
    public bool IsAlarmOn { get; set; }
}

[TestMethod]
public void it_can_be_injected_as_a_dependency()
{
    //virtual time has to be 1000*3.75 faster to get to an hour 
    //in 1000 ms real time
    var dateTime = DateTime.Now.ToVirtualTime(1000 * 3.75);
    var numberOfHoursBeforeAlarmSounds = 1;
    var alarmClock = new AlarmClock(dateTime, numberOfHoursBeforeAlarmSounds);
    Assert.IsFalse(alarmClock.IsAlarmOn);
    System.Threading.Thread.Sleep(1000);
    Assert.IsTrue(alarmClock.IsAlarmOn);
}

এছাড়া কোড পরীক্ষা সম্পর্কে একটি ভাল পঠিত এখানে Ayende দ্বারা তারিখসময় উপর নির্ভর করে ayende.com/blog/3408/dealing-with-time-in-tests
স্যামুয়েল

1

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

public static class Clock
{
    private static Func<DateTime> _utcNow = () => DateTime.UtcNow;

    static AsyncLocal<Func<DateTime>> _override = new AsyncLocal<Func<DateTime>>();

    public static DateTime UtcNow => (_override.Value ?? _utcNow)();

    public static void Set(Func<DateTime> func)
    {
        _override.Value = func;
    }

    public static void Reset()
    {
        _override.Value = null;
    }
}

Https://gist.github.com/CraftyFella/42f459f7687b0b8b268fc311e6b4af08 থেকে উত্সাহিত


1

একটি পুরানো প্রশ্ন, কিন্তু এখনও বৈধ।

আমার দৃষ্টিভঙ্গি System.DateTime.Nowকলটি মোড়ানোর জন্য একটি নতুন ইন্টারফেস এবং শ্রেণি তৈরি করা

public interface INow
{
    DateTime Execute();
}

public sealed class Now : INow
{
    public DateTime Execute()
    {
        return DateTime.Now
    }
}

এই ইন্টারফেসটি যে কোনও ক্লাসে ইনজেক্ট করা যেতে পারে যার বর্তমান তারিখ এবং সময় পাওয়া দরকার। এই উদাহরণে, আমার একটি বর্গ রয়েছে যা বর্তমান তারিখ এবং সময়কে একটি টাইমস্প্যান যোগ করে (একটি ইউনিট টেস্টেবল সিস্টেম.ডেটটাইম.নো। অ্যাড (টাইমস্প্যান))

public interface IAddTimeSpanToCurrentDateAndTime
{
    DateTime Execute(TimeSpan input);
}

public class AddTimeSpanToCurrentDateAndTime : IAddTimeSpanToCurrentDateAndTime
{
    private readonly INow _now;

    public AddTimeSpanToCurrentDateAndTime(INow now)
    {
        this._now = now;
    }

    public DateTime Execute(TimeSpan input)
    {
        var currentDateAndTime = this._now.Execute();

        return currentDateAndTime.Add(input);
    }
}

এবং পরীক্ষা সঠিকভাবে কাজ করে তা নিশ্চিত করার জন্য এটি লেখা যেতে পারে। আমি নুনিট এবং মক ব্যবহার করছি তবে যে কোনও পরীক্ষার কাঠামোটি করবে

public class Execute
{
    private Moq.Mock<INow> _nowMock;

    private AddTimeSpanToCurrentDateAndTime _systemUnderTest;

    [SetUp]
    public void Initialize()
    {
        this._nowMock = new Moq.Mock<INow>(Moq.MockBehavior.Strict);

        this._systemUnderTest = AddTimeSpanToCurrentDateAndTime(
            this._nowMock.Object);
    }

    [Test]
    public void AddTimeSpanToCurrentDateAndTimeExecute0001()
    {
        // arrange

        var input = new TimeSpan(911252);

        // arrange : mocks

        this._nowMock
            .Setup(a => a.Execute())
            .Returns(new DateTime(348756););

        // arrange : expected

        var expected = new DateTime(911252 + 348756);

        // act

        var actual = this._systemUnderTest.Execute(input).Result;

        // assert

        Assert.Equals(actual, expected);
    }
}

এই প্যাটার্ন কোনও ফাংশন যা বাইরের মত উপর নির্ভর করে কাজ করবে System.Random.Next(), System.DateTime.Now.UtcNow, System.Guid.NewGuid()ইত্যাদি

আরও উদাহরণের জন্য https://loadload.visualstudio.com/Stamina/_git/Stamina.Core দেখুন বা https://www.nuget.org/packages/Stamina.Core nuget প্যাকেজ পান।


1

তুমি ক্লাসে পরিবর্তন করতে পারেন আপনি একটি ব্যবহার করতে পরীক্ষা Func<DateTime>এটা কন্সট্রাকটর প্যারামিটার মাধ্যমে যা হস্তান্তর করা হবে, তাই যখন আপনি বাস্তব কোডে ক্লাসের নিদর্শনের সঙ্গে তৈরি করেন, আপনি পাস করতে পারেন () => DateTime.UtcNowথেকেFunc<DateTime> প্যারামিটার হয়, এবং পরীক্ষা উপর, সময় পাস করতে পারেন পরীক্ষা করতে ইচ্ছুক।

উদাহরণ স্বরূপ:

    [TestMethod]
    public void MyTestMethod()
    {
        var instance = new MyClass(() => DateTime.MinValue);
        Assert.AreEqual(instance.MyMethod(), DateTime.MinValue);
    } 

    public void RealWorldInitialization()
    {
        new MyClass(() => DateTime.UtcNow);
    }

    class MyClass
    {
        private readonly Func<DateTime> _utcTimeNow;

        public MyClass(Func<DateTime> UtcTimeNow)
        {
            _utcTimeNow = UtcTimeNow;
        }

        public DateTime MyMethod()
        {
            return _utcTimeNow();
        }
    }

1
আমি এই উত্তর পছন্দ। যাইহোক আমি যা জড়ো করেছি তা থেকে, এটি সি # বিশ্বে চোখের পাতায় উত্থিত হতে পারে যেখানে শ্রেণি / অবজেক্টগুলিতে আরও ফোকাস রয়েছে। যেভাবেই হোক না কেন, আমি এটিকে পছন্দ করি কারণ এটি আমার কাছে যা ঘটছে তা সত্যই সহজ এবং স্পষ্ট।
সিউডোরামبل

0

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

public class DateTimeProvider
{
    protected static DateTime? DateTimeNow;
    protected static DateTime? DateTimeUtcNow;

    public DateTime Now
    {
        get
        {
            return DateTimeNow ?? System.DateTime.Now;
        }
    }

    public DateTime UtcNow
    {
        get
        {
            return DateTimeUtcNow ?? System.DateTime.UtcNow;
        }
    }

    public static DateTimeProvider DateTime
    {
        get
        {
            return new DateTimeProvider();
        }
    }

    protected DateTimeProvider()
    {       
    }
}

পরীক্ষার জন্য, পরীক্ষার প্রকল্পে একটি সহায়ক তৈরি করে যা সেটগুলির সাথে কাজ করবে,

public class MockDateTimeProvider : DateTimeProvider
{
    public static void SetNow(DateTime now)
    {
        DateTimeNow = now;
    }

    public static void SetUtcNow(DateTime utc)
    {
        DateTimeUtcNow = utc;
    }

    public static void RestoreAsDefault()
    {
        DateTimeNow = null;
        DateTimeUtcNow = null;
    }
}

কোডে

var dateTimeNow = DateTimeProvider.DateTime.Now         //not DateTime.Now
var dateTimeUtcNow = DateTimeProvider.DateTime.UtcNow   //not DateTime.UtcNow

এবং পরীক্ষায়

[Test]
public void Mocked_Now()
{
    DateTime now = DateTime.Now;
    MockDateTimeProvider.SetNow(now);    //set to mock
    Assert.AreEqual(now, DateTimeProvider.DateTime.Now);
    Assert.AreNotEqual(now, DateTimeProvider.DateTime.UtcNow);
}

[Test]
public void Mocked_UtcNow()
{
    DateTime utcNow = DateTime.UtcNow;
    MockDateTimeProvider.SetUtcNow(utcNow);   //set to mock
    Assert.AreEqual(utcNow, DateTimeProvider.DateTime.UtcNow);
    Assert.AreNotEqual(utcNow, DateTimeProvider.DateTime.Now);
}

তবে একটি জিনিস মনে রাখা দরকার, কিছু সময় আসল ডেটটাইম এবং সরবরাহকারীর ডেটটাইম একই রকম হয় না

[Test]
public void Now()
{
    Assert.AreEqual(DateTime.Now.Kind, DateTimeProvider.DateTime.Now.Kind);
    Assert.LessOrEqual(DateTime.Now, DateTimeProvider.DateTime.Now);
    Assert.LessOrEqual(DateTimeProvider.DateTime.Now - DateTime.Now, TimeSpan.FromMilliseconds(1));
}

আমি ধরে নিয়েছি যে শ্রদ্ধাটি সর্বাধিক টাইমস্প্যান.ফর্মমিলিসেকেন্ডগুলি (0.00002) হবে । তবে বেশিরভাগ সময় এটি আরও কম হয়

মকসাম্পলে নমুনাটি সন্ধান করুন


0

এই প্রশ্নের আমার উত্তর এখানে। আমি 'অ্যাম্বিয়েন্ট কনটেক্সট' প্যাটার্নটি আইডিসপোজেবলের সাথে সংযুক্ত করি। সুতরাং আপনি ডেটটাইমপ্রাইভাইডারটি ব্যবহার করতে পারেন urrent আপনার সাধারণ প্রোগ্রাম কোডে এবং পরীক্ষায় আপনি ব্যবহারের বিবৃতি দিয়ে স্কোপটিকে ওভাররাইড করে।

using System;
using System.Collections.Immutable;


namespace ambientcontext {

public abstract class DateTimeProvider : IDisposable
{
    private static ImmutableStack<DateTimeProvider> stack = ImmutableStack<DateTimeProvider>.Empty.Push(new DefaultDateTimeProvider());

    protected DateTimeProvider()
    {
        if (this.GetType() != typeof(DefaultDateTimeProvider))
            stack = stack.Push(this);
    }

    public static DateTimeProvider Current => stack.Peek();
    public abstract DateTime Today { get; }
    public abstract DateTime Now {get; }

    public void Dispose()
    {
        if (this.GetType() != typeof(DefaultDateTimeProvider))
            stack = stack.Pop();
    }

    // Not visible Default Implementation 
    private class DefaultDateTimeProvider : DateTimeProvider {
        public override DateTime Today => DateTime.Today; 
        public override DateTime Now => DateTime.Now; 
    }
}
}

ইউনিট-টেস্টের মধ্যে উপরের ডেটটাইমপ্রোভাইডারটি কীভাবে ব্যবহার করবেন তা এখানে

using System;
using Xunit;

namespace ambientcontext
{
    public class TestDateTimeProvider
    {
        [Fact]
        public void TestDateTime()
        {
            var actual = DateTimeProvider.Current.Today;
            var expected = DateTime.Today;

            Assert.Equal<DateTime>(expected, actual);

            using (new MyDateTimeProvider(new DateTime(2012,12,21)))
            {
                Assert.Equal(2012, DateTimeProvider.Current.Today.Year);

                using (new MyDateTimeProvider(new DateTime(1984,4,4)))
                {
                    Assert.Equal(1984, DateTimeProvider.Current.Today.Year);    
                }

                Assert.Equal(2012, DateTimeProvider.Current.Today.Year);
            }

            // Fall-Back to Default DateTimeProvider 
            Assert.Equal<int>(expected.Year,  DateTimeProvider.Current.Today.Year);
        }

        private class MyDateTimeProvider : DateTimeProvider 
        {
            private readonly DateTime dateTime; 

            public MyDateTimeProvider(DateTime dateTime):base()
            {
                this.dateTime = dateTime; 
            }

            public override DateTime Today => this.dateTime.Date;

            public override DateTime Now => this.dateTime;
        }
    }
}

0

ব্যবহার করে ITimeProviderআমরা এটিকে বিশেষ ভাগ করা সাধারণ প্রকল্পে নিতে বাধ্য হয়েছিলাম যা অবশ্যই অন্যান্য অন্যান্য প্রকল্পের থেকে উল্লেখ করা উচিত। তবে এটি নির্ভরতা নিয়ন্ত্রণকে জটিল করে তোলে

আমরা ITimeProviderনেট নেট ফ্রেমওয়ার্কটিতে অনুসন্ধান করেছি। আমরা নিউগেট প্যাকেজটি অনুসন্ধান করেছি এবং এমন একটি পেয়েছি যা কাজ করতে পারে না DateTimeOffset

সুতরাং আমরা আমাদের নিজস্ব সমাধান নিয়ে এসেছি, যা কেবলমাত্র স্ট্যান্ডার্ড লাইব্রেরির ধরণের উপর নির্ভর করে। আমরা একটি উদাহরণ ব্যবহার করছি Func<DateTimeOffset>

ব্যবহারবিধি

public class ThingThatNeedsTimeProvider
{
    private readonly Func<DateTimeOffset> now;
    private int nextId;

    public ThingThatNeedsTimeProvider(Func<DateTimeOffset> now)
    {
        this.now = now;
        this.nextId = 1;
    }

    public (int Id, DateTimeOffset CreatedAt) MakeIllustratingTuple()
    {
        return (nextId++, now());
    }
}

কিভাবে নিবন্ধন করবেন

Autofac

builder.RegisterInstance<Func<DateTimeOffset>>(() => DateTimeOffset.Now);

( ভবিষ্যতের সম্পাদকদের জন্য: আপনার কেসগুলি এখানে সংযোজন করুন )।

কিভাবে ইউনিট পরীক্ষা

public void MakeIllustratingTuple_WhenCalled_FillsCreatedAt()
{
    DateTimeOffset expected = CreateRandomDateTimeOffset();
    DateTimeOffset StubNow() => expected;
    var thing = new ThingThatNeedsTimeProvider(StubNow);

    var (_, actual) = thing.MakeIllustratingTuple();

    Assert.AreEqual(expected, actual);
}

0

সম্ভবত কম পেশাদার তবে সহজ সমাধানটি ভোক্তা পদ্ধতিতে একটি ডেটটাইম প্যারামিটার তৈরি করা যেতে পারে example উদাহরণস্বরূপ, নমুনা মেঠোডের মতো পদ্ধতি তৈরির পরিবর্তে প্যারামিটার দিয়ে নমুনা মেঠোড 1 তৈরি করুন S

public void SampleMethod()
    {
        DateTime anotherDateTime = DateTime.Today.AddDays(-10);
        if ((DateTime.Now-anotherDateTime).TotalDays>10)
        {

        }
    }
    public void SampleMethod1(DateTime dateTimeNow)
    {
        DateTime anotherDateTime = DateTime.Today.AddDays(-10);
        if ((dateTimeNow - anotherDateTime).TotalDays > 10)
        {

        }

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