คุณจะทดสอบเอนโค้ดเดอร์ได้อย่างไร


9

ฉันมีสิ่งนี้:

public byte[] EncodeMyObject(MyObject obj)

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

byte[] expectedResults = new byte[3]{ 0x01, 0x02, 0xFF };
Assert.IsEqual(expectedResults, EncodeMyObject(myObject));

แก้ไข: สองวิธีที่ฉันเห็นเสนอคือ:

1) การใช้ค่าที่คาดไว้ของฮาร์ดโค้ดเช่นตัวอย่างด้านบน

2) การใช้ตัวถอดรหัสเพื่อถอดรหัสอาร์เรย์ไบต์ที่เข้ารหัสและเปรียบเทียบวัตถุอินพุต / เอาต์พุต

ปัญหาที่ฉันเห็นด้วยวิธีที่ 1 คือมันเปราะมากและต้องใช้ค่าฮาร์ดโค้ดจำนวนมาก

ปัญหาเกี่ยวกับวิธีที่ 2 คือการทดสอบตัวเข้ารหัสขึ้นอยู่กับตัวถอดรหัสทำงานอย่างถูกต้อง หากตัวเข้ารหัส / ตัวถอดรหัสแตกเท่ากัน (ในที่เดียวกัน) การทดสอบอาจทำให้เกิดผลบวกปลอม

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


4
วิธีการที่ไม่myObjectไปจากmyObjectไป{ 0x01, 0x02, 0xFF }? อัลกอริทึมนั้นสามารถพังและทดสอบได้หรือไม่? เหตุผลที่ฉันถามอยู่ในขณะนี้ดูเหมือนว่าคุณมีการทดสอบที่พิสูจน์ได้ว่าสิ่งมหัศจรรย์สิ่งหนึ่งผลิตสิ่งมหัศจรรย์อีก ความมั่นใจเพียงอย่างเดียวของคุณคืออินพุตเดียวสร้างเอาต์พุตเดียว หากคุณสามารถทำลายอัลกอริทึมคุณสามารถเพิ่มความมั่นใจในอัลกอริทึมและพึ่งพาการอินพุตและเอาต์พุตเวทมนตร์น้อยลง
Anthony Pegram

3
@Codism จะเกิดอะไรขึ้นถ้าตัวเข้ารหัสและตัวถอดรหัสแตกในที่เดียวกัน
ConditionRacer

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

1
@ Justin984 เอาล่ะตอนนี้เรากำลังจะลึก ฉันจะไม่เปิดเผย internals ส่วนตัวเหล่านั้นในฐานะสมาชิกของ Encoder API ไม่แน่นอน ฉันจะลบพวกเขาออกจาก Encoder ทั้งหมด หรือค่อนข้าง Encoder จะมอบหมายออกไปที่อื่นที่พึ่งพา หากเป็นการต่อสู้ระหว่างวิธีการมอนสเตอร์ที่ไม่สามารถทดสอบได้หรือคลาสผู้ช่วยเหลือฉันจะเลือกคลาสตัวช่วยทุกครั้ง แต่อีกครั้งฉันกำลังทำการอ้างถึงโค้ดของคุณโดยไม่รู้ข้อมูล ณ จุดนี้เนื่องจากฉันมองไม่เห็น แต่ถ้าคุณต้องการเพิ่มความมั่นใจในการทดสอบของคุณการมีวิธีการที่น้อยลงในการทำสิ่งต่าง ๆ น้อยลงเป็นวิธีที่จะไปถึงที่นั่น
Anthony Pegram

1
@ Justin984 หากข้อมูลจำเพาะเปลี่ยนไปคุณเปลี่ยนผลลัพธ์ที่ต้องการในการทดสอบและตอนนี้มันล้มเหลว จากนั้นคุณเปลี่ยนลอจิกตัวเข้ารหัสเพื่อผ่าน ดูเหมือนว่า TDD ควรทำงานอย่างไรและจะล้มเหลวก็ต่อเมื่อควร ฉันไม่เห็นว่าสิ่งนี้ทำให้เปราะได้อย่างไร
Daniel Kaplan

คำตอบ:


1

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

สิ่งที่ฉันทำคือพยายามทำลายสิ่งต่าง ๆ ตามระดับของสิ่งที่เป็นนามธรรม

ดังนั้นฉันจะเริ่มต้นด้วยบางสิ่งบางอย่างในระดับบิตที่ฉันจะทดสอบสิ่งที่ชอบ

bitWriter = new BitWriter();
bitWriter.writeInt(42, bits = 7);
assertEqual( bitWriter.data(), {0x42} )

ดังนั้นแนวคิดก็คือนักเขียนบิตรู้วิธีเขียนฟิลด์ประเภทดั้งเดิมที่สุดเช่น ints

ประเภทที่ซับซ้อนมากขึ้นจะถูกนำมาใช้โดยใช้และทดสอบสิ่งที่ชอบ:

bitWriter = new BitWriter();
writeDate(bitWriter, new Datetime(2001, 10, 4));

bitWriter2 = new BitWriter();
bitWriter2.writeInt(2001, 12)
bitWriter2.writeInt(10, 4)
bitWriter2.writeInt(4, 6)

assertEquals(bitWriter.data(), bitWriter2.data() )

ขอให้สังเกตว่าสิ่งนี้จะช่วยหลีกเลี่ยงความรู้เกี่ยวกับวิธีการบรรจุบิตจริง นั่นคือการทดสอบโดยการทดสอบก่อนหน้านี้และสำหรับการทดสอบนี้เราจะสมมติว่ามันใช้งานได้

จากนั้นในระดับต่อไปของสิ่งที่เป็นนามธรรมที่เรามี

bitWriter = new BitWriter();
encodeObject(bitWriter, myObject);


bitWriter2 = new BitWriter();
bitWriter2.writeInt(42, 32)
writeDate(bitWriter2, new Datetime(2001, 10, 4));
writeVarString(bitWriter2, "alphanumeric");

assertEquals(bitWriter.data(), bitWriter2.data() )

ดังนั้นอีกครั้งเราไม่พยายามที่จะรวมความรู้เกี่ยวกับวิธีการเข้ารหัส varstrings หรือวันที่หรือตัวเลขจริง ในการทดสอบนี้เราสนใจเฉพาะการเข้ารหัสที่ผลิตโดย encodeObject

ผลลัพธ์ที่ได้คือถ้ารูปแบบวันที่มีการเปลี่ยนแปลงคุณจะต้องแก้ไขการทดสอบที่เกี่ยวข้องกับวันที่ แต่รหัสและการทดสอบอื่น ๆ ทั้งหมดไม่เกี่ยวข้องกับวิธีการเข้ารหัสวันที่จริงและเมื่อคุณอัปเดตรหัสเพื่อให้ ใช้งานได้การทดสอบทั้งหมดนั้นจะผ่านไปได้ด้วยดี


ฉันชอบสิ่งนี้. ฉันเดาว่านี่คือสิ่งที่ผู้วิจารณ์คนอื่นพูดถึงเกี่ยวกับการแบ่งมันเป็นชิ้นเล็ก ๆ มันไม่ได้หลีกเลี่ยงปัญหาอย่างสมบูรณ์เมื่อข้อมูลจำเพาะเปลี่ยนแปลง แต่ทำให้ดีขึ้น
ConditionRacer

6

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

หากมีห้องเลื้อยที่มีเอาต์พุตอื่นเช่นเดียวกับในมาตรฐาน MPEG (เช่นมีผู้ดำเนินการบางอย่างที่คุณสามารถนำไปใช้กับอินพุตได้ แต่คุณมีอิสระในการแลกเปลี่ยนความพยายามในการเข้ารหัสเมื่อเทียบกับคุณภาพผลผลิตหรือพื้นที่จัดเก็บ) กำหนดกลยุทธ์การถอดรหัสให้กับเอาต์พุตและตรวจสอบว่ามันเหมือนกับอินพุท - หรือถ้าการเข้ารหัสสูญเสียนั่นก็ใกล้เคียงกับอินพุทดั้งเดิม มันยากที่จะเขียนโปรแกรม แต่ปกป้องคุณจากการปรับปรุงในอนาคตที่อาจเกิดกับโปรแกรมเปลี่ยนไฟล์ของคุณ


2
สมมติว่าคุณใช้ตัวถอดรหัสและเปรียบเทียบค่า จะเกิดอะไรขึ้นถ้าตัวเข้ารหัสและตัวถอดรหัสทั้งคู่แตกในที่เดียวกัน ตัวเข้ารหัสเข้ารหัสไม่ถูกต้องและตัวถอดรหัสถอดรหัสอย่างไม่ถูกต้อง แต่วัตถุอินพุต / เอาต์พุตนั้นถูกต้องเพราะกระบวนการทำไม่ถูกต้องสองครั้ง
ConditionRacer

@ Justin984 จากนั้นใช้ชื่อที่เรียกว่า "test vectors" รู้คู่อินพุต / เอาต์พุตที่คุณสามารถใช้อย่างแม่นยำเพื่อทดสอบตัวเข้ารหัสและตัวถอดรหัส
ratchet freak

@ ratchet freak นั่นทำให้ฉันกลับไปทดสอบด้วยค่าที่คาดหวัง ซึ่งเป็นเรื่องปกตินั่นคือสิ่งที่ฉันกำลังทำอยู่ แต่มันเปราะเล็กน้อยดังนั้นฉันจึงมองหาว่ามีวิธีที่ดีกว่านี้หรือไม่
ConditionRacer

1
นอกเหนือจากการอ่านมาตรฐานอย่างละเอียดและสร้างกรณีทดสอบสำหรับทุกกฎแล้วไม่มีวิธีที่จะหลีกเลี่ยงได้ว่าตัวเข้ารหัสและตัวถอดรหัสประกอบด้วยข้อผิดพลาดเดียวกัน ตัวอย่างเช่นสมมติว่า "ABC" ต้องแปลเป็น "xyz" แต่ตัวเข้ารหัสไม่ทราบและตัวถอดรหัสของคุณจะไม่เข้าใจ "xyz" หากพบว่าเคย ผลงานแบบ handcrafted ไม่มีลำดับ "ABC" เนื่องจากโปรแกรมเมอร์ไม่ทราบถึงกฎนั้นและการทดสอบด้วยการเข้ารหัส / ถอดรหัสสตริงสุ่มจะส่งผ่านอย่างไม่ถูกต้องเนื่องจากทั้งตัวเข้ารหัสและตัวถอดรหัสไม่สนใจปัญหา
281377

1
เพื่อช่วยจับข้อบกพร่องที่มีผลต่อตัวถอดรหัสและตัวเข้ารหัสที่เขียนด้วยตัวเองเนื่องจากขาดความรู้ให้ใช้ความพยายามในการรับเอาท์พุทตัวเข้ารหัสจากผู้ขายรายอื่น และลองทดสอบเอาท์พุทเครื่องเข้ารหัสของคุณกับเครื่องถอดรหัสของ บริษัท อื่น ไม่มีทางเลือกอื่นรอบตัว

3

ทดสอบที่และencode(decode(coded_value)) == coded_value decode(encode(value)) == valueคุณสามารถให้อินพุตแบบสุ่มในการทดสอบหากคุณต้องการ

ยังคงเป็นไปได้ว่าทั้งตัวเข้ารหัสและตัวถอดรหัสจะเสียรูปแบบฟรี แต่ก็ดูไม่น่าจะเป็นไปได้เลยถ้าคุณไม่มีความเข้าใจผิดเกี่ยวกับมาตรฐานการเข้ารหัส การทดสอบตัวเข้ารหัสและตัวถอดรหัส (เช่นเดียวกับที่คุณทำอยู่แล้ว) การทดสอบฮาร์ดโค้ดควรป้องกันสิ่งนั้น

หากคุณสามารถเข้าถึงการใช้งานอื่นของสิ่งนี้ที่เป็นที่รู้จักในการทำงานอย่างน้อยคุณสามารถใช้มันเพื่อรับความมั่นใจว่าการใช้งานของคุณจะดีแม้ว่าการใช้ในการทดสอบหน่วยจะเป็นไปไม่ได้


ฉันยอมรับว่าข้อผิดพลาดของตัวเข้ารหัส / ถอดรหัสเสริมไม่น่าเป็นไปได้ ในกรณีเฉพาะของฉันรหัสสำหรับคลาสตัวเข้ารหัส / ตัวถอดรหัสถูกสร้างขึ้นโดยเครื่องมืออื่นโดยยึดตามกฎจากฐานข้อมูล ดังนั้นข้อผิดพลาดที่เกิดขึ้นจึงเกิดขึ้นเป็นครั้งคราว
ConditionRacer

จะมี 'ข้อผิดพลาดฟรี' ได้อย่างไร นั่นหมายความว่ามีข้อกำหนดภายนอกสำหรับรูปแบบการเข้ารหัสและด้วยเหตุนี้จึงเป็นตัวถอดรหัสภายนอก
วินไคลน์

ฉันไม่เข้าใจการใช้คำภายนอก แต่มีข้อกำหนดสำหรับวิธีการเข้ารหัสข้อมูลและตัวถอดรหัส ข้อผิดพลาดแบบอภินันทนาการคือที่ตัวเข้ารหัสและตัวถอดรหัสทำงานทั้งคู่ในลักษณะที่เกื้อหนุน แต่แตกต่างจากสเปค ฉันมีตัวอย่างในความคิดเห็นภายใต้คำถามเดิม
ConditionRacer

หากเครื่องเข้ารหัสควรใช้ ROT13 แต่ไม่ได้ตั้งใจ ROT14 และเครื่องถอดรหัสก็ทำเช่นนั้นให้ถอดรหัส (encode ('a')) == 'a' แต่ตัวเข้ารหัสยังคงใช้งานไม่ได้ สำหรับสิ่งที่ซับซ้อนกว่านั้นอาจเป็นไปได้น้อยกว่าที่สิ่งนั้นจะเกิดขึ้น แต่ในทางทฤษฎีแล้วมันอาจทำได้
Michael Shaw

@MichaelShaw เป็นแค่เรื่องไม่สำคัญตัวเข้ารหัสและตัวถอดรหัสสำหรับ ROT13 ก็เหมือนกัน ROT13 เป็นสิ่งที่ตรงกันข้าม หากคุณใช้งาน ROT14 โดยไม่ได้ตั้งใจก็decode(encode(char))จะไม่เท่ากันchar(จะเท่ากับchar+2)
Tom Marthenal

2

ทดสอบความต้องการ

หากความต้องการเป็นเพียง 'เข้ารหัสไปยังสตรีมไบต์ที่เมื่อถอดรหัสสร้างวัตถุที่เทียบเท่า' แล้วเพียงทดสอบตัวเข้ารหัสโดยการถอดรหัส หากคุณกำลังเขียนทั้งตัวเข้ารหัสและตัวถอดรหัสให้ลองทดสอบด้วยกัน พวกเขาไม่มี "ข้อผิดพลาดที่ตรงกัน" หากพวกเขาทำงานร่วมกันแล้วการทดสอบจะผ่าน

หากมีข้อกำหนดอื่น ๆ สำหรับกระแสข้อมูลคุณจะต้องทดสอบโดยการตรวจสอบข้อมูลที่เข้ารหัส

หากรูปแบบการเข้ารหัสถูกกำหนดไว้ล่วงหน้าคุณจะต้องตรวจสอบข้อมูลที่เข้ารหัสกับผลลัพธ์ที่คาดหวังเช่นเดียวกับที่คุณทำหรือ (ดีกว่า) รับตัวถอดรหัสอ้างอิงที่เชื่อถือได้เพื่อทำการตรวจสอบ การใช้ตัวถอดรหัสอ้างอิงช่วยลดความเป็นไปได้ที่คุณจะตีความข้อกำหนดรูปแบบที่ไม่ถูกต้อง


1

ทั้งนี้ขึ้นอยู่กับกรอบการทดสอบและกระบวนทัศน์ที่คุณใช้คุณยังสามารถใช้รูปแบบการจัดเรียง Act Act Assert สำหรับสิ่งนี้เช่นที่คุณพูด

[TestMethod]
public void EncodeMyObject_ForValidInputs_Encodes()
{
    //Arrange object under test
    MyEncoder encoderUnderTest = new MyEncoder();
    MyObject validObject = new MyOjbect();
    //arrange object for condition under test

    //Act
    byte[] actual = encoderUnderTest.EncodeMyObject(myObject);

    //Assert
    byte[] expected = new byte[3]{ 0x01, 0x02, 0xFF };
    Assert.IsEqual(expected, actual);
}

คุณควรทราบข้อกำหนดสำหรับEncodeMyObject()และสามารถใช้รูปแบบนี้เพื่อทดสอบกับแต่ละข้อสำหรับเกณฑ์ที่ถูกต้องและไม่ถูกต้องโดยการจัดเรียงแต่ละข้อและเข้ารหัสแบบผลลัพธ์ที่คาดหวังไว้expectedเช่นเดียวกับตัวถอดรหัส

เนื่องจากคาดว่าจะมีการเข้ารหัสยากสิ่งเหล่านี้จะบอบบางหากคุณมีการเปลี่ยนแปลงครั้งใหญ่

คุณอาจจะสามารถที่จะทำงานโดยอัตโนมัติกับสิ่งที่พารามิเตอร์ขับเคลื่อน (มีลักษณะที่Pex ) หรือถ้าคุณกำลังทำ DDD หรือ BDD มีลักษณะที่Gerkin / แตงกวา


1

คุณต้องตัดสินใจว่าอะไรสำคัญกับคุณ

เป็นสิ่งสำคัญสำหรับคุณหรือไม่ที่ Object มีชีวิตรอดในการเดินทางไปกลับและรูปแบบการโยงที่แม่นยำนั้นไม่สำคัญจริง ๆ หรือ หรือรูปแบบสายที่แน่นอนเป็นส่วนสำคัญของการทำงานของตัวเข้ารหัสและตัวถอดรหัสของคุณหรือไม่?

หากอดีตกว่าเพียงแค่ให้แน่ใจว่าวัตถุอยู่รอดในการเดินทางรอบ หากทั้งตัวเข้ารหัสและตัวถอดรหัสแตกในลักษณะที่สอดคล้องกันอย่างสมบูรณ์คุณไม่สนใจเลย

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.