การทดสอบหน่วยสำหรับการเรียกผู้รับมอบสิทธิ์แบบอะซิงโครนัสใน c #

ฉันมีฟังก์ชันที่สร้างการมอบหมายและเริ่ม BeginInrigg บนวัตถุนั้น โดยมีฟังก์ชันอื่นถูกส่งผ่านไปเพื่อรอ EndInrigg:

    private static void DeploymentComponentThreadedCallBack(IAsyncResult ar)
    {
        var result = (AsyncResult)ar;
        var pluginExecuteAction = (Action<int, Guid, int, EnvironmentServerComponentSet, string>)result.AsyncDelegate;
        pluginExecuteAction.EndInvoke(ar);
        //report back to WCF service that thread is finished
    }

public void DeployComponent(byte[] resource, Guid componentGuid, string deploymentType, Dictionary<string, object> args)
{
  var asyncCallback = new AsyncCallback(DeploymentComponentThreadedCallBack);
  IDeployComponent plugin = GetPluginDelegate();
  Action<byte[], Guid, string, Dictionary<string, object>> pluginExecuteAction = plugin.DeployComponent;
  IAsyncResult ar = pluginExecuteAction.BeginInvoke(resource, componentGuid, deploymentType, args, asyncCallback, null);
}

ฉันต้องการทดสอบหน่วยนี้ แต่เมื่อทำเช่นนั้น DeploymentComponentThreadedCallBack จะไม่โดนโจมตี และเห็นได้ชัดว่า EndInrigg ไม่มีการเรียกเช่นกัน ฉันคิดว่าสิ่งนี้เกิดขึ้นเนื่องจากการทดสอบผ่านไปก่อนที่เธรดแบบอะซิงโครนัสจะสิ้นสุด ดังนั้นเธรดจึงหยุดดำเนินการก่อน EndInrigg แต่มีวิธีที่ฉันสามารถหยุดสิ่งนี้เกิดขึ้นเพื่อที่ฉันจะได้เห็นว่า EndInrigg ได้รับผลกระทบหรือไม่

ไชโยแมตต์


person Bob Tway    schedule 31.08.2011    source แหล่งที่มา


คำตอบ (3)


ฉันคิดว่าปัญหาพื้นฐานของคุณคือคุณไม่ได้เปิดเผยสิ่งใดในวิธีการ DeployComponent ที่จะช่วยให้คุณสามารถติดตามการดำเนินการแบบอะซิงโครนัสที่คุณเริ่มต้นที่นั่น หากคุณส่งคืน IAsyncResult จากที่นั่น คุณสามารถโทร ar.AsyncWaitHandle.WaitOne() เพื่อรอจนกว่าจะเสร็จสิ้น

person RandomEngy    schedule 31.08.2011
comment
น่าเศร้าที่นี่คือโค้ดตัวอย่าง - ในความเป็นจริง DeployComponent ทำสิ่งต่าง ๆ มากมายนอกเหนือจากนั้น และมันมีประเภทการส่งคืนบูลอยู่แล้ว ขอบคุณสำหรับข้อเสนอแนะ - person Bob Tway; 01.09.2011
comment
คุณจะต้องแก้ปัญหานั้นด้วยวิธีใดวิธีหนึ่ง หากคุณต้องการรอให้การดำเนินการเสร็จสิ้น คุณต้องเปิดเผยบางสิ่งเพื่อให้ผู้โทรรอ ภายใต้สถานการณ์ปกติ คุณจะดำเนินการต่อและไม่รอให้เสร็จสิ้น แต่ในการทดสอบ คุณจะรอให้การทดสอบเสร็จสิ้น จริงๆ แล้วคุณสามารถเปลี่ยน DeployComponent ให้ติดตาม APM และรายงานความสำเร็จเมื่อทุกสิ่งที่เริ่มดำเนินการเสร็จสิ้น อาจต้องมีการปรับโครงสร้างเล็กน้อย - person RandomEngy; 02.09.2011

เท่าที่ฉันจำ AsyncResult ได้ มีแฟล็ก (IsCompleted) ที่บอกคุณว่าการดำเนินการกำลังเกิดขึ้นหรือไม่ รอสักครู่ (เช่น ดั้งเดิมด้วยการวนซ้ำ while) จากนั้นทำตามการยืนยันของคุณ

person flq    schedule 31.08.2011
comment
มีแฟล็กดังกล่าว แต่ฉันจะไปที่มันในวัตถุที่เรียกได้อย่างไร เช่น หากเมธอด DeployComponent อยู่บนวัตถุ Foo และในการทดสอบของฉัน ฉันเรียก Foo.DeployComponent(byteStream, new Guid(), cmd, null); ฉันจะรับ AsyncResult ได้จากที่ไหนเพื่อดูว่าเสร็จแล้วหรือไม่ - person Bob Tway; 31.08.2011
comment
ฉันไม่เห็นว่าคุณจะมาจากไหน คุณกำลังส่ง Asyncresult ไปยังวิธีแรก ดังนั้นคุณสามารถรอก่อนส่งผ่านเข้าไปได้ - person flq; 31.08.2011
comment
อา ฉันเห็นสิ่งที่คุณหมายถึง นั่นจะไม่ได้ผล เนื่องจากภายใต้สถานการณ์ปกติ ฉันไม่ต้องการรออีกต่อไป - เฉพาะการทดสอบนี้เท่านั้น ไม่อย่างนั้นคงไม่มีประโยชน์อะไรที่จะทำแบบอะซิงโครนัส - person Bob Tway; 31.08.2011
comment
แมตต์ สิ่งที่ขาดหายไปคือการทดสอบของคุณ มันไม่สามารถมองเห็นได้ว่าคุณมาจากไหน หากคุณไม่ให้สิทธิ์ตัวเองในการเข้าถึง AsyncHandle คุณอาจจะโชคไม่ดี - person flq; 31.08.2011

คุณเพียงแค่ต้องสร้างจุดฉีดเพื่อเปลี่ยนการโทรแบบอะซิงโครนัสเป็นการบล็อคการโทร ตัวอย่างเช่น:

 public class MethodInvoker
 {
     public virtual void Invoke(Action begin, Action<IAsyncResult> end)
     {
          begin.BeginInvoke(end, null);
     }
 }

ด้วยเวอร์ชันการทดสอบหน่วยดังนี้:

 public class SynchronousInvoker : MethodInvoker
 {
     public override void Invoke(Action begin, Action<IAsyncResult> end)
     {
         begin();
         end();
     }
 }

จากนั้นคุณจะเขียนโค้ดดังนี้:

 _myMethodInvoker.Invoke(pluginExecuteAction, asyncCallback);

ซึ่งในบริบทของฟังก์ชันการทำงานปกติของคุณนั้น เป็นแบบอะซิงโครนัส ในการทดสอบหน่วยของคุณ คุณเพียงแค่ฉีด SynchronousInviver เข้าไปที่ตำแหน่งนั้น และมันจะกลายเป็นการบล็อคการโทร

person Tejs    schedule 31.08.2011
comment
ดูเหมือนจะเป็นแนวทางที่ดี แต่ฉันไม่สามารถปรับแต่งเพื่อให้ได้ผลได้ BeginInrigg ต้องใช้พารามิเตอร์ประเภท AsyncResult ไม่ใช่ Action‹IAsyncResult› และหากไม่มี Action คุณจะไม่สามารถเรียก end() ได้ - person Bob Tway; 01.09.2011