มีวิธีที่ดีกว่าในการเขียนการทดสอบหน่วยกว่าชุดของ 'AssertEquals' หรือไม่?


12

นี่คือตัวอย่างพื้นฐานของการทดสอบหน่วยของฉันที่ต้องใช้โดยใช้ qunit:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>

<link rel="stylesheet" href="qunit/qunit-1.13.0.css">
<script src = "qunit/qunit-1.13.0.js"></script>
<script src = "../js/fuzzQuery.js"></script>

<script>

test("Fuzz Query Basics", function()
        {
            equal(fuzzQuery("name:(John Smith)"), "name:(John~ Smith~)");
            equal(fuzzQuery("name:Jon~0.1"), "name:Jon~0.1");
            equal(fuzzQuery("Jon"), "Jon~");
            //etc

        }
    );

</script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>

ตอนนี้ฉันคิดว่านี่เป็นเรื่องซ้ำ ๆ

สามารถใส่อินพุต / เอาต์พุตทั้งหมดลงในอาร์เรย์และวนรอบมันได้

test("Fuzz Query Basics", function()
        {
            var equals = [
                           ["name:(John Smith)", "name:(John~ Smith~)"],
                           ["name:Jon~0.1", "name:Jon~0.1"],
                           ["Jon", "Jon~"]
                           ];

            for (var i = 0; i<equals.length; i++)
                {
                    equal(fuzzQuery(equals[i][0]), equals[i][1]);               
                }

        }
    );

และใช้งานได้ดี

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

ในแง่ของความสามารถในการอ่านฉันไม่คิดว่ามันจะเป็นข้อสรุป แต่อย่างใด

คุณสามารถใส่เคส / อินพุตในไฟล์ CSV แยกซึ่งอาจทำให้แก้ไขได้ง่ายขึ้น

คำถามคืออะไร - อนุสัญญาทั่วไปเกี่ยวกับการเขียนการทดสอบหน่วยเหล่านี้คืออะไร?

มีเหตุผลที่คุณไม่ควรใส่มันลงในอาร์เรย์หรือไม่?


ทั้งสองอย่างนี้จะบอกคุณว่าค่าใดล้มเหลวหรือไม่
JeffO

1
@JeffO - ใช่ - ด้วย QUnit - หากการทดสอบล้มเหลวเอาต์พุตจะแสดงค่าที่คาดหวังและค่าจริง
dwjohnston

คำตอบ:


8

การทดสอบ refactored ของคุณมีกลิ่น: เงื่อนไขการทดสอบลอจิก

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

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

การแก้ปัญหาเช่นเคยคือการเลื่อนระดับนามธรรม ใช้กรอบการทดสอบที่ให้การทดสอบแบบกำหนดพารามิเตอร์ให้คุณเช่นxUnit.NETหรือบริบท (ข้อจำกัดความรับผิดชอบ: ฉันเขียนบริบท) สิ่งนี้จะช่วยให้คุณจัดกลุ่มการทดสอบการจำแนกตำแหน่งสำหรับพฤติกรรมเดียวกันร่วมกันในลักษณะที่เป็นธรรมชาติในขณะที่ยังคงทำการทดสอบแยกพฤติกรรมแยกต่างหาก


เป็นคำถามที่ดีโดยทาง
Benjamin Hodgson

1
1) หากคุณเลื่อนระดับของนามธรรมคุณไม่ได้ซ่อนรายละเอียดแบบเดียวกันกับที่คุณบอกว่ากำลังถูกบดบังโดยวง for? 2) ไม่แน่ใจว่าการทดสอบแบบมีพารามิเตอร์สามารถใช้ได้ที่นี่ ดูเหมือนว่าจะมีสิ่งที่คล้ายคลึงกันอยู่ที่นี่ แต่ฉันมีสถานการณ์มากมายคล้ายกับ OPs ที่ฉันมีชุดข้อมูลที่มีค่า 10-20 และต้องการเรียกใช้พวกเขาทั้งหมดผ่าน SUT ใช่แต่ละค่าจะแตกต่างกันและอาจทดสอบชื่อดังต่างกัน แต่ดูเหมือนว่าชื่อการทดสอบ "ประดิษฐ์" จริงสำหรับทุกค่าเดียวจะเป็นค่าเกินจริง ฉันพบว่าอัตราส่วนค่า / ขนาดรหัสที่ดีที่สุดในการใช้งานที่คล้ายกัน ...
DXM

... ลูป ตราบใดที่การทดสอบล้มเหลวผู้ยืนยันจะพิมพ์สิ่งที่ล้มเหลวอย่างแน่นอนนักพัฒนามีข้อเสนอแนะมากพอที่จะระบุปัญหาได้อย่างแม่นยำ
DXM

@DXM 1) เฟรมเวิร์กการทดสอบจัดเตรียมฟังก์ชันการทดสอบแบบพาราเมตริก เราเชื่อมั่นในกรอบการทดสอบโดยปริยายดังนั้นเราจึงไม่ได้เขียนแบบทดสอบ 2) การทดสอบแบบพาราเมตริกมีจุดประสงค์เพื่อจุดประสงค์นี้อย่างแน่นอน: คุณกำลังทำขั้นตอนเดียวกันทุกครั้ง แต่มีค่าอินพุต / เอาต์พุตต่างกัน เฟรมเวิร์กการทดสอบช่วยให้คุณไม่จำเป็นต้องเขียนชื่อสำหรับแต่ละรายการด้วยการรันอินพุตที่แตกต่างกันผ่านวิธีการทดสอบเดียวกัน
Benjamin Hodgson

5

ดูเหมือนว่าคุณต้องการทดสอบหน่วยที่ขับเคลื่อนด้วยข้อมูล เมื่อคุณพูดถึงการใช้ QUnit ฉันพบปลั๊กอินที่เปิดใช้การทดสอบแบบพารามิเตอร์:

https://github.com/AStepaniuk/qunit-parameterize

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

โค้ดตัวอย่างสำหรับ GitHub README:

QUnit
    .cases([
        { a : 2, b : 2, expectedSum : 4 },
        { a : 5, b : 5, expectedSum : 10 },
        { a : 40, b : 2, expectedSum : 42 }
    ])
    .test("Sum test", function(params) {
        var actualSum = sum(params.a, params.b);
        equal(actualSum, params.expectedSum);
    });

1
ตกลงดูเหมือนว่าการทดสอบที่ขับเคลื่อนด้วยข้อมูล แต่ดูเหมือนว่านั่นคือสิ่งที่เขามีอยู่แล้วในตัวอย่างโค้ดที่สองของเขา
Robert Harvey

1
@RobertHarvey - ถูกต้อง มีคำศัพท์ที่ยอมรับได้สำหรับสิ่งที่เขาพยายามทำให้สำเร็จและมีปลั๊กอินสำหรับกรอบการทดสอบที่ใช้เพื่อให้ง่ายต่อการเขียนการทดสอบประเภทนี้ ฉันคิดว่ามันคุ้มค่าที่จะสังเกตคำตอบสำหรับอนาคตนั่นคือทั้งหมด
Greg Burghardt

1

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

นี่ช่วยให้ฉันบอกได้ทันทีว่าการทดสอบ / อินพุตใดที่ล้มเหลว


0

ฉันชอบแนวทางที่สองของคุณ แต่ฉันจะเพิ่ม 2 คะแนน

  • อย่าใช้อาร์เรย์ในการจัดเก็บข้อมูลที่ทดสอบเนื่องจากการทำงานกับดัชนีเป็นวิธีที่ไม่สะอาด
  • ห้ามใช้forลูป

`

[
    {
        process: "name:(John Smith)",
        result: "name:(John~ Smith~)"
    },
    {
        process: "name:Jon~0.1", 
        result: "name:Jon~0.1"
    },
    {
        process: "Jon", 
        result: "Jon~"
    }
]
.forEach(function(data){

    var result = fuzzQuery(data.process);
    equal(result, data.result);
});

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

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