System.out.println () এর জন্য JUnit পরীক্ষা


370

আমাকে পুরানো অ্যাপ্লিকেশনটির জন্য JUnit পরীক্ষা লিখতে হবে যা খারাপভাবে ডিজাইন করা হয়েছে এবং স্ট্যান্ডার্ড আউটপুটটিতে অনেক ত্রুটি বার্তা লিখছে। getResponse(String request)পদ্ধতিটি সঠিকভাবে আচরণ করলে এটি একটি এক্সএমএল প্রতিক্রিয়া দেয়:

@BeforeClass
public static void setUpClass() throws Exception {
    Properties queries = loadPropertiesFile("requests.properties");
    Properties responses = loadPropertiesFile("responses.properties");
    instance = new ResponseGenerator(queries, responses);
}

@Test
public void testGetResponse() {
    String request = "<some>request</some>";
    String expResult = "<some>response</some>";
    String result = instance.getResponse(request);
    assertEquals(expResult, result);
}

কিন্তু যখন এটি ত্রুটিযুক্ত এক্সএমএল হয়ে যায় বা অনুরোধটি বুঝতে না পারে এটি ফিরে আসে nullএবং কিছু স্ট্যান্ডার্ড স্ট্যান্ডার্ড আউটপুটে লিখে দেয়।

JUnit এ কনসোল আউটপুট চাপানোর কোনও উপায় আছে কি? যেমন ধরার জন্য:

System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());

সম্পর্কে, কিন্তু সদৃশ না stackoverflow.com/questions/3381801/...
Raedwald

উত্তর:


581

বাইটআরআউটপুট স্ট্রিম এবং System.setXXX ব্যবহার করা সহজ:

private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;

@Before
public void setUpStreams() {
    System.setOut(new PrintStream(outContent));
    System.setErr(new PrintStream(errContent));
}

@After
public void restoreStreams() {
    System.setOut(originalOut);
    System.setErr(originalErr);
}

নমুনা পরীক্ষার কেস:

@Test
public void out() {
    System.out.print("hello");
    assertEquals("hello", outContent.toString());
}

@Test
public void err() {
    System.err.print("hello again");
    assertEquals("hello again", errContent.toString());
}

কমান্ড লাইন বিকল্পটি পরীক্ষা করার জন্য আমি এই কোডটি ব্যবহার করেছি (সংস্করণটির স্ট্রিং ইত্যাদি আউটপুট হিসাবে জোর দেওয়া)

সম্পাদনা করুন:System.setOut(null) পরীক্ষার পরে ডাকা এই উত্তরটির পূর্ববর্তী সংস্করণগুলি ; এটি নালপয়েন্টারএক্সপেক্টস কমেন্টারদের উল্লেখ করার কারণ।


ফার্স্টমোর, আমি প্রতিক্রিয়াগুলির জন্য পরীক্ষার জন্য জুনিটম্যাচারগুলি ব্যবহার করেছি: assertThat (ফলাফল, এতে স্ট্রিং রয়েছে ("<অনুরোধ: getEmployeeByKeyResponse")); ধন্যবাদ, ডিএফএ
মাইক মিনিকি

3
আমি ভিএমএম চালু হওয়ার সময় প্রবাহটি পুনরায় ফিরিয়ে আনতে সিস্টেম.সেটআউট (নাল) ব্যবহার করতে পছন্দ করি
tddmonkey

5
জাভাদোকরা System.setOut বা System.setErr এ নাল পাস করতে সক্ষম হওয়ার বিষয়ে কিছুই বলে না। আপনি কি নিশ্চিত যে এটি সমস্ত জেআরই-তে কাজ করবে?
ফিনউইউ

55
NullPointerExceptionউপরের পরামর্শ অনুসারে নাল ত্রুটি প্রবাহ সেট করার পরে আমি অন্যান্য পরীক্ষাগুলির মধ্যে মুখোমুখি হয়েছি (ইন java.io.writer(Object), এক্সএমএল যাচাইকারীর দ্বারা অভ্যন্তরীণ নামে পরিচিত)। আমি পরিবর্তে একটি ক্ষেত্রের মধ্যে আসল সংরক্ষণ: oldStdErr = System.errএবং @Afterপদ্ধতিতে এটিকে পুনরুদ্ধার করার পরামর্শ দেব ।
লুক উশরউড

6
দুর্দান্ত সমাধান। এটি যে কেউ ব্যবহার করছে তার জন্য কেবল একটি নোট, আপনাকে আউটসন্টেন্ট থেকে () সাদা স্থান / নিউলাইন ছাঁটাই করতে হতে পারে।
অ্যালিসন

101

আমি জানি এটি একটি পুরানো থ্রেড, তবে এটি করার জন্য একটি দুর্দান্ত গ্রন্থাগার রয়েছে:

সিস্টেম বিধি

দস্তাবেজ থেকে উদাহরণ:

public void MyTest {
    @Rule
    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();

    @Test
    public void overrideProperty() {
        System.out.print("hello world");
        assertEquals("hello world", systemOutRule.getLog());
    }
}

এটি আপনাকে System.exit(-1)কমান্ড লাইন সরঞ্জামের জন্য পরীক্ষা করার প্রয়োজন হবে এমন অন্যান্য জিনিসগুলিকে ফাঁদে ফেলতে এবং অনুমতি দেবে ।


1
এই পদ্ধতির সমস্যাগুলি ভরা কারণ স্ট্যান্ডার্ড আউটপুট স্ট্রিমটি আপনার প্রোগ্রামের সমস্ত অংশের দ্বারা ব্যবহৃত একটি ভাগ করা সংস্থান। এটা প্রমিত আউটপুট স্ট্রিম সরাসরি ব্যবহার নির্মূল করার নির্ভরতা ইনজেকশন ব্যবহার করা ভাল: stackoverflow.com/a/21216342/545127
Raedwald

30

পুনঃনির্দেশ পরিবর্তে System.out, আমি বর্গ refactor হবে ব্যবহারসমূহ System.out.println()একটি ক্ষণস্থায়ী দ্বারা PrintStreamসহযোগী হিসেবে এবং তারপর ব্যবহার System.outউৎপাদনে এবং একটি টেস্ট স্পাই পরীক্ষা। এটি হ'ল স্ট্যান্ডার্ড আউটপুট স্ট্রিমের সরাসরি ব্যবহার বাদ দিতে নির্ভরতা ইনজেকশন ব্যবহার করুন।

উৎপাদন

ConsoleWriter writer = new ConsoleWriter(System.out));

টেস্টে

ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));

আলোচনা

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


1
আমি জেডিকে কোথাও এই কনসোল রাইটারটি খুঁজে পাইনি: এটি কোথায়?
জিন-ফিলিপ কারুয়ানা

3
এটি উত্তরে সম্ভবত উল্লেখ করা উচিত, তবে আমি বিশ্বাস করি যে ক্লাসটি ব্যবহারকারী1909402 দ্বারা তৈরি হয়েছিল।
সেবাস্তিয়ান

6
আমি মনে করি ConsoleWriterএটি পরীক্ষার বিষয়,
নিল ডি ওয়েট

22

আপনি মাধ্যমে System.out মুদ্রণ প্রবাহ সেট করতে পারেন setOut () (এবং জন্য inএবং err)। আপনি কি এটিকে মুদ্রণ স্ট্রিমে পুনর্নির্দেশ করতে পারেন যা কোনও স্ট্রিংয়ে রেকর্ড করে, এবং তারপরে পরিদর্শন করতে পারে? এটি সহজ পদ্ধতি হিসাবে উপস্থিত হবে।

(আমি কোনও পর্যায়ে অ্যাডভোকেট করব, অ্যাপটিকে কিছু লগিং ফ্রেমওয়ার্কে রূপান্তরিত করব - তবে আমি সন্দেহ করি যে আপনি ইতিমধ্যে এটি সম্পর্কে অবগত আছেন!)


1
এটাই আমার মনে এসেছিল তবে আমি বিশ্বাস করতে পারি না যে এটি করার কোনও মানক জুনিত উপায় নেই। ধন্যবাদ, মস্তিষ্ক তবে ক্রেডিটগুলি আসল প্রচেষ্টার জন্য ডিএফএ-তে পেয়েছে।
মাইক মিনিকি

এই পদ্ধতির সমস্যাগুলি ভরা কারণ স্ট্যান্ডার্ড আউটপুট স্ট্রিমটি আপনার প্রোগ্রামের সমস্ত অংশের দ্বারা ব্যবহৃত একটি ভাগ করা সংস্থান। এটা প্রমিত আউটপুট স্ট্রিম সরাসরি ব্যবহার নির্মূল করার নির্ভরতা ইনজেকশন ব্যবহার করা ভাল: stackoverflow.com/a/21216342/545127
Raedwald

হ্যাঁ. আমি এটি দ্বিতীয় এবং সম্ভবত একটি লগিং দৃging় প্রশ্ন করতে হবে (একটি লগিং উপাদান বা অনুরূপ একটি কল চাপানো ভাল)
ব্রায়ান অগ্নি

13

সামান্য বিষয় বন্ধ, কিন্তু ক্ষেত্রে কিছু লোক (আমার মত, যখন আমি প্রথম এই থ্রেড পাওয়া যায়) SLF4J মাধ্যমে লগ আউটপুট ধরে রাখার ব্যাপারে আগ্রহী হতে পারে, কমন্স-পরীক্ষার এর JUnit @Ruleযথাসাধ্য সাহায্য কর!

public class FooTest {
    @Rule
    public final ExpectedLogs logs = new ExpectedLogs() {{
        captureFor(Foo.class, LogLevel.WARN);
    }};

    @Test
    public void barShouldLogWarning() {
        assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.

        // Logic using the class you are capturing logs for:
        Foo foo = new Foo();
        assertThat(foo.bar(), is(not(nullValue())));

        // Assert content of the captured logs:
        assertThat(logs.isEmpty(), is(false));
        assertThat(logs.contains("Your warning message here"), is(true));
    }
}

দাবি অস্বীকার :

  • আমি এই গ্রন্থাগারটি তৈরি করেছি যেহেতু আমি আমার নিজের প্রয়োজনের জন্য কোনও উপযুক্ত সমাধান খুঁজে পাই না।
  • কেবলমাত্র বাইন্ডিংগুলি log4j, log4j2এবং logbackএই মুহুর্তে উপলভ্য, তবে আমি আরও যুক্ত করে খুশি।

এই লাইব্রেরিটি তৈরি করার জন্য আপনাকে অনেক ধন্যবাদ! আমি এতদিন ধরে এরকম কিছু খুঁজছিলাম! এটি খুব, খুব দরকারী কারণ আপনি সহজেই পরীক্ষাযোগ্য হওয়ার জন্য আপনার কোডটি সহজতর করতে পারবেন না, তবে লগ বার্তা দিয়ে আপনি বিস্ময়কর করতে পারেন!
carlspring

এটি সত্যিই আশাব্যঞ্জক দেখাচ্ছে ... তবে আমি যখন কেবল আপনার এটিএমটিস্ট প্রোগ্রামটি অনুলিপি করেছি এবং গ্রেডলের অধীনে এটি একটি পরীক্ষা হিসাবে চালাচ্ছি তখনও আমি একটি ব্যতিক্রম পাচ্ছি ... আমি আপনার গিথুব পৃষ্ঠায় একটি সমস্যা উত্থাপন করেছি ...
মাইক রডেন্ট

9

@ ডিএফএ উত্তরটি দুর্দান্ত, সুতরাং আউটপুট ব্লকগুলি পরীক্ষা করা সম্ভব করার জন্য আমি এটি আরও দূরে নিয়েছি।

প্রথমে আমি TestHelperএমন একটি পদ্ধতি তৈরি করেছি captureOutputযা বিরক্তিকর শ্রেণিকে গ্রহণ করে CaptureTest। ক্যাপচার আউটপুট পদ্ধতি আউটপুট স্ট্রিমগুলি সেট এবং ছিন্ন করার কাজ করে। CaptureOutputএর testপদ্ধতির বাস্তবায়নটি যখন ডাকা হয় তখন পরীক্ষার ব্লকের আউটপুটটিতে এটির অ্যাক্সেস থাকে।

টেস্টহেল্পারের উত্স:

public class TestHelper {

    public static void captureOutput( CaptureTest test ) throws Exception {
        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        ByteArrayOutputStream errContent = new ByteArrayOutputStream();

        System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));

        test.test( outContent, errContent );

        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
        System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));

    }
}

abstract class CaptureTest {
    public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}

নোট করুন যে টেস্টহেল্পার এবং ক্যাপচারটেষ্ট একই ফাইলটিতে সংজ্ঞায়িত হয়েছে।

তারপরে আপনার পরীক্ষায়, আপনি স্থির ক্যাপচারআউটপুট আমদানি করতে পারেন। এখানে JUnit ব্যবহার করে একটি উদাহরণ দেওয়া হয়েছে:

// imports for junit
import static package.to.TestHelper.*;

public class SimpleTest {

    @Test
    public void testOutput() throws Exception {

        captureOutput( new CaptureTest() {
            @Override
            public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {

                // code that writes to System.out

                assertEquals( "the expected output\n", outContent.toString() );
            }
        });
}

7

যদি আপনি স্প্রিং বুট ব্যবহার করে থাকেন (আপনি উল্লেখ করেছেন যে আপনি কোনও পুরানো অ্যাপ্লিকেশন নিয়ে কাজ করছেন, সুতরাং আপনি সম্ভবত এটি না কিন্তু এটি অন্যের কাজে লাগতে পারে), তবে আপনি org.springframework.boot.test.rule.OutputCapture ব্যবহার করতে পারেন নিম্নলিখিত পদ্ধতিতে:

@Rule
public OutputCapture outputCapture = new OutputCapture();

@Test
public void out() {
    System.out.print("hello");
    assertEquals(outputCapture.toString(), "hello");
}

1
আমি আপনার উত্তরে ভোট দিয়েছি কারণ আমি স্প্রিং বুট ব্যবহার করি এবং এটি আমাকে সঠিক পথে রাখে। ধন্যবাদ! তবে আউটপুট ক্যাপচারটি আরম্ভ করা দরকার। (সর্বজনীন আউটপুটক্যাপচার আউটপুটক্যাপচার = নতুন আউটপুটক্যাপচার ();) দেখুন ডকসস.স্প্রিং.ইউ
স্প্রিং-

আপনি একেবারে সঠিক। মন্তব্যের জন্য ধন্যবাদ! আমি আমার উত্তর আপডেট করেছি।
ডিসার

4

@ ডিএফএর উত্তর এবং অন্য উত্তরের উপর ভিত্তি করে যা দেখায় যে System.in কীভাবে পরীক্ষা করা যায় , আমি কোনও প্রোগ্রামকে ইনপুট দেওয়ার জন্য এবং তার আউটপুট পরীক্ষা করার জন্য আমার সমাধানটি ভাগ করতে চাই।

একটি রেফারেন্স হিসাবে, আমি JUnit 4.12 ব্যবহার করি।

ধরা যাক আমাদের এই প্রোগ্রামটি রয়েছে যা কেবলমাত্র আউটপুটে ইনপুটটিকে প্রতিলিপি করে:

import java.util.Scanner;

public class SimpleProgram {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print(scanner.next());
        scanner.close();
    }
}

এটি পরীক্ষা করতে, আমরা নিম্নলিখিত ক্লাসটি ব্যবহার করতে পারি:

import static org.junit.Assert.*;

import java.io.*;

import org.junit.*;

public class SimpleProgramTest {
    private final InputStream systemIn = System.in;
    private final PrintStream systemOut = System.out;

    private ByteArrayInputStream testIn;
    private ByteArrayOutputStream testOut;

    @Before
    public void setUpOutput() {
        testOut = new ByteArrayOutputStream();
        System.setOut(new PrintStream(testOut));
    }

    private void provideInput(String data) {
        testIn = new ByteArrayInputStream(data.getBytes());
        System.setIn(testIn);
    }

    private String getOutput() {
        return testOut.toString();
    }

    @After
    public void restoreSystemInputOutput() {
        System.setIn(systemIn);
        System.setOut(systemOut);
    }

    @Test
    public void testCase1() {
        final String testString = "Hello!";
        provideInput(testString);

        SimpleProgram.main(new String[0]);

        assertEquals(testString, getOutput());
    }
}

আমি খুব বেশি ব্যাখ্যা করব না, কারণ আমি বিশ্বাস করি কোডটি পাঠযোগ্য এবং আমি আমার উত্সগুলি উদ্ধৃত করেছি।

JUnit চললে testCase1(), সাহায্যকারী পদ্ধতিগুলি যেভাবে প্রদর্শিত হবে সেটিকে কল করতে চলেছে:

  1. setUpOutput(), @Beforeটীকা দেওয়ার কারণে
  2. provideInput(String data)থেকে ডাকা হয়েছে testCase1()
  3. getOutput()থেকে ডাকা হয়েছে testCase1()
  4. restoreSystemInputOutput(), @Afterটীকা দেওয়ার কারণে

আমি পরীক্ষা করিনি System.errকারণ আমার এটির প্রয়োজন ছিল না, তবে এটি কার্যকর করা সহজ হওয়া উচিত, পরীক্ষার মতো System.out


1

আপনি system.out স্ট্রিমটিকে পুনঃনির্দেশ করতে চান না কারণ এটি পুরো JVM এর জন্য পুনঃনির্দেশ করে। জেভিএমে চলমান অন্য যে কোনও কিছু গোলমাল হতে পারে। ইনপুট / আউটপুট পরীক্ষা করার আরও ভাল উপায় আছে। স্টাব / বিদ্রূপগুলি দেখুন।


1

পরীক্ষার জন্য সম্পূর্ণ JUnit 5 উদাহরণ System.out(কখন অংশটি প্রতিস্থাপন করুন):

package learning;

import static org.assertj.core.api.BDDAssertions.then;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class SystemOutLT {

    private PrintStream originalSystemOut;
    private ByteArrayOutputStream systemOutContent;

    @BeforeEach
    void redirectSystemOutStream() {

        originalSystemOut = System.out;

        // given
        systemOutContent = new ByteArrayOutputStream();
        System.setOut(new PrintStream(systemOutContent));
    }

    @AfterEach
    void restoreSystemOutStream() {
        System.setOut(originalSystemOut);
    }

    @Test
    void shouldPrintToSystemOut() {

        // when
        System.out.println("example");

        then(systemOutContent.toString()).containsIgnoringCase("example");
    }
}

0

JUnit ব্যবহার করার সময় আপনি system.out.println ব্যবহার করে বা লগার এপিআই ব্যবহার করে সরাসরি মুদ্রণ করতে পারবেন না । আপনি যদি কোনও মান পরীক্ষা করতে চান তবে আপনি সহজেই ব্যবহার করতে পারেন

Assert.assertEquals("value", str);

এটি দৃ error়তা ত্রুটির নীচে ফেলে দেবে:

java.lang.AssertionError: expected [21.92] but found [value]

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

 Assert.assertEquals(21.92, str);

0

বাইরে জন্য

@Test
void it_prints_out() {

    PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));

    System.out.println("Hello World!");
    assertEquals("Hello World!\r\n", out.toString());

    System.setOut(save_out);
}

ভুলের জন্য

@Test
void it_prints_err() {

    PrintStream save_err=System.err;final ByteArrayOutputStream err= new ByteArrayOutputStream();System.setErr(new PrintStream(err));

    System.err.println("Hello World!");
    assertEquals("Hello World!\r\n", err.toString());

    System.setErr(save_err);
}

এই ধরণের সেটআপ এবং টিয়ারডাউন যুক্তির জন্য আমি @Ruleআপনার পরীক্ষায় এটি ইনলাইন না করে একটি ব্যবহার করব। উল্লেখযোগ্যভাবে, যদি আপনার দাবিটি ব্যর্থ হয় তবে দ্বিতীয় System.setOut/Errকলটি পৌঁছানো যাবে না
dimo414
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.