মডেলস্টেটটি কীভাবে উপহাস করবেন? মোখ ফ্রেমওয়ার্কটি ব্যবহার করে অসমর্থিত?


91

আমি ModelState.IsValidআমার নিয়ামক অ্যাকশন পদ্ধতিতে যাচাই করে যা এইরকম একটি কর্মচারী তৈরি করে:

[HttpPost]
public virtual ActionResult Create(EmployeeForm employeeForm)
{
    if (this.ModelState.IsValid)
    {
        IEmployee employee = this._uiFactoryInstance.Map(employeeForm);
        employee.Save();
    }

    // Etc.
}

আমি মোখ ফ্রেমওয়ার্ক ব্যবহার করে আমার ইউনিট পরীক্ষা পদ্ধতিতে এটি উপহাস করতে চাই। আমি এটিকে উপহাস করার চেষ্টা করেছি:

var modelState = new Mock<ModelStateDictionary>();
modelState.Setup(m => m.IsValid).Returns(true);

তবে এটি আমার ইউনিট পরীক্ষার ক্ষেত্রে একটি ব্যতিক্রম ছুঁড়েছে। কেউ কি আমাকে এখানে সাহায্য করতে পারবেন?

উত্তর:


142

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

// arrange
_controllerUnderTest.ModelState.AddModelError("key", "error message");

// act
// Now call the controller action and it will 
// enter the (!ModelState.IsValid) condition
var actual = _controllerUnderTest.Index();

আমরা কীভাবে মডেলস্টেট সেট করব? সত্য মামলায় আঘাত করতে আইসভালিড? মডেলস্টেটের কোনও সেটর নেই, এবং তাই আমরা নিম্নলিখিতগুলি করতে পারি না: _controllerUnderTest.ModelState.IsValid = সত্য। এটি ছাড়া, এটি কর্মচারীকে আঘাত করবে না
করণ

4
@ নিউটন, এটি ডিফল্টরূপে সত্য। সত্যিকারের ক্ষেত্রে আঘাত করার জন্য আপনাকে কিছু নির্দিষ্ট করার দরকার নেই। আপনি যদি মিথ্যা মামলায় আঘাত করতে চান তবে আমার উত্তর হিসাবে প্রদর্শিত হিসাবে আপনি কেবল একটি মডেলস্টেট ত্রুটি যুক্ত করুন।
দারিন দিমিত্রভ

আইএমএইচও উন্নততর সমাধানটি এমভিসি পরিবাহক ব্যবহার করা। এইভাবে আপনি আপনার নিয়ামকের আরও বাস্তবসম্মত আচরণ পান, আপনার নিয়তির - বৈশিষ্ট্যের বৈধতাগুলিতে মডেল বৈধতা সরবরাহ করা উচিত। নীচের পোস্টটি এটি বর্ণনা করছে ( স্ট্যাকওভারফ্লো.
com/a/5580363/

13

উপরের সমাধানটির সাথে আমার একমাত্র সমস্যাটি হ'ল আমি যদি বৈশিষ্ট্যগুলি সেট করি তবে এটি আসলে মডেলটি পরীক্ষা করে না। আমি এইভাবে আমার নিয়ামক সেটআপ করি।

private HomeController GenerateController(object model)
    {
        HomeController controller = new HomeController()
        {
            RoleService = new MockRoleService(),
            MembershipService = new MockMembershipService()
        };
        MvcMockHelpers.SetFakeAuthenticatedControllerContext(controller);

        // bind errors modelstate to the controller
        var modelBinder = new ModelBindingContext()
        {
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
            ValueProvider = new NameValueCollectionValueProvider(new NameValueCollection(), CultureInfo.InvariantCulture)
        };
        var binder = new DefaultModelBinder().BindModel(new ControllerContext(), modelBinder);
        controller.ModelState.Clear();
        controller.ModelState.Merge(modelBinder.ModelState);
        return controller;
    }

মডেলবাইন্ডার অবজেক্টটি এমন একটি জিনিস যা মডেলের বৈধতা পরীক্ষা করে। এইভাবে আমি কেবলমাত্র অবজেক্টের মান নির্ধারণ করতে এবং এটি পরীক্ষা করতে পারি।


4
খুব সুন্দর, আমি ঠিক তাই খুঁজছিলাম আমি জানি না যে কত লোক এই জাতীয় কোনও পুরানো প্রশ্নে পোস্ট করে তবে এটি আমার জন্য আপনার মূল্যবান ছিল। ধন্যবাদ
ডব্লিউ জ্যাকসন

দুর্দান্ত সমাধান হিসাবে মনে হচ্ছে, এখনও
ম্যাট

4
এই জাতীয় কিছু দিয়ে আলাদাভাবে মডেলটি পরীক্ষা করা ভাল না? stackoverflow.com/a/4331964/3198973
রাবারডাক

4
যদিও এটি একটি চতুর সমাধান, আমি @ রাবারডাকের সাথে একমত। এটি একটি আসল, বিচ্ছিন্ন ইউনিট-পরীক্ষা হওয়ার জন্য, মডেলের বৈধতাটির নিজস্ব পরীক্ষা হওয়া উচিত, যখন নিয়ামকের পরীক্ষার নিজস্ব পরীক্ষা করা উচিত। যদি মডেলটি মডেলবাইন্ডার বৈধতা লঙ্ঘন করতে পরিবর্তিত হয়, তবে আপনার নিয়ামক পরীক্ষা ব্যর্থ হবে, যা নিয়ামক যুক্তি ভাঙ্গেনি। একটি অবৈধ মডেলস্টেট অভিধান অভিধান পরীক্ষা করার জন্য, কেবলমাত্র মডেলস্টেটের জন্য একটি জাল মডেলস্টেট ত্রুটি যুক্ত করুন sআইএস ভালিড চেক ব্যর্থ হওয়ার জন্য।
xDaevax

2

ইউড্রাইভের উত্তর আমাকে পথের অংশ নিয়েছে তবে কিছু ফাঁক এখনও রয়েছে। ইনপুটটিতে কোনও ডেটা ছাড়াই new NameValueCollectionValueProvider(), মডেল বাইন্ডারটি নিয়ামকটিকে কোনও খালি মডেলকে আবদ্ধ করবে, modelবস্তুর সাথে নয়।

এটি ঠিক আছে - আপনার মডেলটিকে কেবল একটি হিসাবে সিরিয়াল করুন NameValueCollection, এবং তারপরে এটি NameValueCollectionValueProviderকনস্ট্রাক্টরে পাস করুন । ভাল, বেশ না। দুর্ভাগ্যক্রমে, এটি আমার ক্ষেত্রে কার্যকর হয়নি কারণ আমার মডেলটিতে একটি সংগ্রহ রয়েছে এবং সংগ্রহগুলি এটি দুর্দান্তভাবে NameValueCollectionValueProviderখেলছে না।

JsonValueProviderFactoryযদিও রেসকিউ এখানে আসে। এটি DefaultModelBinderযতক্ষণ না আপনি "application/json" একটি সামগ্রীর ধরণের নির্দিষ্ট করতে পারেন এবং আপনার ক্রমিক জেএসওএন বিষয়টিকে আপনার অনুরোধের ইনপুট প্রবাহে পাস করবেন ততক্ষণ এটি ব্যবহার করা যেতে পারে (দয়া করে নোট করুন, কারণ এই ইনপুট স্ট্রিমটি একটি মেমরি স্ট্রিম, একে স্মরণ হিসাবে নির্বিঘ্নে ছেড়ে দেওয়া ঠিক আছে স্ট্রিম কোনও বাহ্যিক সংস্থান ধরে রাখে না):

protected void BindModel<TModel>(Controller controller, TModel viewModel)
{
    var controllerContext = SetUpControllerContext(controller, viewModel);
    var bindingContext = new ModelBindingContext
    {
        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModel, typeof(TModel)),
        ValueProvider = new JsonValueProviderFactory().GetValueProvider(controllerContext)
    };

    new DefaultModelBinder().BindModel(controller.ControllerContext, bindingContext);
    controller.ModelState.Clear();
    controller.ModelState.Merge(bindingContext.ModelState);
}

private static ControllerContext SetUpControllerContext<TModel>(Controller controller, TModel viewModel)
{
    var controllerContext = A.Fake<ControllerContext>();
    controller.ControllerContext = controllerContext;
    var json = new JavaScriptSerializer().Serialize(viewModel);
    A.CallTo(() => controllerContext.Controller).Returns(controller);
    A.CallTo(() => controllerContext.HttpContext.Request.InputStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes(json)));
    A.CallTo(() => controllerContext.HttpContext.Request.ContentType).Returns("application/json");
    return controllerContext;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.