কোনও লগারে কোনও বার্তায় জুনিট কীভাবে দৃsert়তা জানায়


205

আমার কিছু কোড-আন্ডার-টেস্ট রয়েছে যা জাভা লগারকে তার অবস্থানের প্রতিবেদন করার জন্য কল করে। JUnit পরীক্ষা কোডে, আমি যাচাই করতে চাই যে এই লগারে সঠিক লগ এন্ট্রি করা হয়েছিল। নিম্নলিখিত লাইন বরাবর কিছু:

methodUnderTest(bool x){
    if(x)
        logger.info("x happened")
}

@Test tester(){
    // perhaps setup a logger first.
    methodUnderTest(true);
    assertXXXXXX(loggedLevel(),Level.INFO);
}

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

উত্তর:


142

আমি এটি বেশ কয়েকবার প্রয়োজন। আমি নীচে একটি ছোট নমুনা রেখেছি, যা আপনি আপনার প্রয়োজনের সাথে সামঞ্জস্য করতে চান। মূলত, আপনি নিজের তৈরি করেন Appenderএবং এটি আপনার পছন্দমতো লগারে যুক্ত করুন। আপনি যদি সমস্ত কিছু সংগ্রহ করতে চান তবে রুট লগার শুরু করার জন্য ভাল জায়গা, তবে আপনি চাইলে আরও নির্দিষ্ট ব্যবহার করতে পারেন। আপনার কাজ শেষ হয়ে গেলে অ্যাপেন্ডারটিকে সরাতে ভুলবেন না, অন্যথায় আপনি মেমরি ফাঁস তৈরি করতে পারেন। নীচে আমি এটি পরীক্ষার মধ্যেই করেছি তবে আপনার প্রয়োজনের উপর নির্ভর করে বা setUpবা @Beforeএবং হতে পারে আরও ভাল জায়গা।tearDown@After

এছাড়াও, নীচের বাস্তবায়ন Listমেমরিতে সমস্ত কিছু সংগ্রহ করে । আপনি যদি খুব বেশি লগইন করেন তবে আপনি বোরিং এন্ট্রিগুলি ফেলে দেওয়ার জন্য, বা ডিস্কের অস্থায়ী ফাইলে লগটি লেখার জন্য ইঙ্গিতটি লিখতে বিবেচনা করতে পারেন (ইঙ্গিত: LoggingEventহ'ল Serializable, তাই যদি আপনার লগ বার্তাটি থাকে তবে ইভেন্ট ইভেন্টটি কেবল সিরিয়ালাইজ করতে সক্ষম হবেন) হয়।)

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class MyTest {
    @Test
    public void test() {
        final TestAppender appender = new TestAppender();
        final Logger logger = Logger.getRootLogger();
        logger.addAppender(appender);
        try {
            Logger.getLogger(MyTest.class).info("Test");
        }
        finally {
            logger.removeAppender(appender);
        }

        final List<LoggingEvent> log = appender.getLog();
        final LoggingEvent firstLogEntry = log.get(0);
        assertThat(firstLogEntry.getLevel(), is(Level.INFO));
        assertThat((String) firstLogEntry.getMessage(), is("Test"));
        assertThat(firstLogEntry.getLoggerName(), is("MyTest"));
    }
}

class TestAppender extends AppenderSkeleton {
    private final List<LoggingEvent> log = new ArrayList<LoggingEvent>();

    @Override
    public boolean requiresLayout() {
        return false;
    }

    @Override
    protected void append(final LoggingEvent loggingEvent) {
        log.add(loggingEvent);
    }

    @Override
    public void close() {
    }

    public List<LoggingEvent> getLog() {
        return new ArrayList<LoggingEvent>(log);
    }
}

4
এটি দুর্দান্ত কাজ করে। আমি কেবলমাত্র উন্নতি করব তা হল কল করা logger.getAllAppenders(), তারপরে পদক্ষেপ এবং appender.setThreshold(Level.OFF)প্রত্যেককে কল করা (এবং আপনার কাজ শেষ হয়ে গেলে সেগুলি পুনরায় সেট করুন!)। এটি নিশ্চিত করে যে আপনি যে "খারাপ" বার্তাগুলি তৈরি করার চেষ্টা করছেন তা পরীক্ষার লগগুলিতে প্রদর্শিত হবে না এবং পরবর্তী বিকাশকারীকে ফ্রিক আউট করে।
কোডার 11

1
Log4j 2.x সালে সামান্য বেশি হিসাবে আপনি একটি প্লাগইন তৈরি করা প্রয়োজন সংবর্ত হয়, এই একটি চেহারা আছে: stackoverflow.com/questions/24205093/...
paranza

1
এর জন্য ধন্যবাদ. আপনি যদি লগব্যাক ব্যবহার করছেন তবে আপনি ListAppender<ILoggingEvent>নিজের কাস্টম অ্যাপেন্ডার তৈরির পরিবর্তে ব্যবহার করতে পারেন ।
sinujohn

2
কিন্তু এটি slf4j এর জন্য কাজ করে না! আপনি কি জানেন যে আমি কীভাবে এটির সাথে এটি কাজ করতে পারি?
শিলান

3
@sd আপনি কাস্ট যদি Loggerকরতে org.apache.logging.log4j.core.Logger(ইন্টারফেসের জন্য বাস্তবায়ন বর্গ) আপনি অ্যাক্সেস পাবেন setAppender()/removeAppender()আবার।
ডেভিড মোলস

59

এখানে একটি সহজ এবং দক্ষ লগব্যাক সমাধান।
এটি কোনও নতুন ক্লাস যুক্ত / তৈরি করার প্রয়োজন হয় না।
এটি নির্ভর করে ListAppender: একটি হোয়াইটবক্স লগব্যাক অ্যাপেন্ডার যেখানে একটি public Listক্ষেত্রের মধ্যে লগ এন্ট্রি যুক্ত করা হয় যা আমরা আমাদের দৃser়তার জন্য ব্যবহার করতে পারি।

এখানে একটি সহজ উদাহরণ।

ফু ক্লাস:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Foo {

    static final Logger LOGGER = LoggerFactory.getLogger(Foo .class);

    public void doThat() {
        LOGGER.info("start");
        //...
        LOGGER.info("finish");
    }
}

ফুটেস্ট ক্লাস:

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;

public class FooTest {

    @Test
    void doThat() throws Exception {
        // get Logback Logger 
        Logger fooLogger = (Logger) LoggerFactory.getLogger(Foo.class);

        // create and start a ListAppender
        ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
        listAppender.start();

        // add the appender to the logger
        // addAppender is outdated now
        fooLogger.addAppender(listAppender);

        // call method under test
        Foo foo = new Foo();
        foo.doThat();

        // JUnit assertions
        List<ILoggingEvent> logsList = listAppender.list;
        assertEquals("start", logsList.get(0)
                                      .getMessage());
        assertEquals(Level.INFO, logsList.get(0)
                                         .getLevel());

        assertEquals("finish", logsList.get(1)
                                       .getMessage());
        assertEquals(Level.INFO, logsList.get(1)
                                         .getLevel());
    }
}

তালিকার উপাদানগুলির নির্দিষ্ট কিছু বৈশিষ্ট্য যুক্ত করতে JUnit জোরগুলি খুব অভিযোজিত শোনায় না।
AssertJ বা Hamcrest হিসাবে ম্যাচার / দৃ as় গ্রন্থাগারগুলি এর জন্য আরও ভাল প্রদর্শিত হবে:

AssertJ এর সাথে এটি হবে:

import org.assertj.core.api.Assertions;

Assertions.assertThat(listAppender.list)
          .extracting(ILoggingEvent::getMessage, ILoggingEvent::getLevel)
          .containsExactly(Tuple.tuple("start", Level.INFO), Tuple.tuple("finish", Level.INFO));

আপনি যদি কোনও ত্রুটি লগ করেন তবে পরীক্ষাটি ব্যর্থ হওয়া থেকে কীভাবে থামবেন?
গিলটিরাস

@ গিলটিরাস আমি বুঝতে পারছি না একটি ত্রুটি লগ করা আপনার পরীক্ষা ব্যর্থ হওয়া উচিত নয়। আপনি কি ব্যাখ্যা?
ডেভিডএক্সএক্সএক্সএক্স

এছাড়াও, mockপরীক্ষা করা হয় যে ক্লাস না মনে রাখবেন । আপনাকে এটি newঅপারেটরের সাথে ইনস্ট্যান্ট করতে হবে
ডাইমাইট্রো চাসোভস্কিই

35

এই (আশ্চর্যজনক) দ্রুত এবং সহায়ক উত্তরের জন্য অনেক ধন্যবাদ; তারা আমার সমাধানের জন্য আমাকে সঠিক পথে রাখে।

কোডবেসটি আমি এটি ব্যবহার করতে চাই, জাভা.ইটিল.লগিংটিকে তার লগার প্রক্রিয়া হিসাবে ব্যবহার করি এবং লোগোজেজে বা ইন্টারফেস / ফেসেক্সগুলিতে লগের সম্পূর্ণরূপে পরিবর্তন করতে আমি এই কোডগুলিতে ঘরে যথেষ্ট অনুভব করি না। তবে এই পরামর্শগুলির উপর ভিত্তি করে আমি 'হ্যাক-আপ' করেছিলাম একটি জুলহ্যান্ডলার এক্সটেনশন এবং এটি ট্রিট হিসাবে কাজ করে।

একটি সংক্ষিপ্তসার অনুসরণ করা। প্রসারিত করুন java.util.logging.Handler:

class LogHandler extends Handler
{
    Level lastLevel = Level.FINEST;

    public Level  checkLevel() {
        return lastLevel;
    }    

    public void publish(LogRecord record) {
        lastLevel = record.getLevel();
    }

    public void close(){}
    public void flush(){}
}

স্পষ্টতই, আপনি আপনার কাছ থেকে যতটা চান / চান / চান ঠিক তেমন সঞ্চয় করতে পারেন LogRecordবা আপনার একটি ওভারফ্লো না হওয়া পর্যন্ত এগুলি সমস্ত স্ট্যাকের মধ্যে ঠেলাতে পারেন।

জুনিট-পরীক্ষার প্রস্তুতির ক্ষেত্রে, আপনি একটি তৈরি করে এতে java.util.logging.Loggerনতুন একটি যুক্ত করুন LogHandler:

@Test tester() {
    Logger logger = Logger.getLogger("my junit-test logger");
    LogHandler handler = new LogHandler();
    handler.setLevel(Level.ALL);
    logger.setUseParentHandlers(false);
    logger.addHandler(handler);
    logger.setLevel(Level.ALL);

কলটি setUseParentHandlers()হ'ল সাধারণ হ্যান্ডলারদের নিঃশব্দ করা, যাতে (এই জুনিট-পরীক্ষার জন্য) অপ্রয়োজনীয় লগিং না ঘটে। আপনার কোড-আন্ডার-টেস্টে এই লগারটি ব্যবহার করার জন্য যা যা করা করুন, পরীক্ষা চালান এবং গুণমানকে দৃsert় করুন:

    libraryUnderTest.setLogger(logger);
    methodUnderTest(true);  // see original question.
    assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
}

(অবশ্যই, আপনি এই কাজের বৃহত অংশটি একটি @Beforeপদ্ধতিতে সরানো এবং বিভিন্ন ধরণের অন্যান্য উন্নতি করতে হবে, তবে এটি এই উপস্থাপনাটিকে বিশৃঙ্খলা করবে))


16

আরেকটি বিকল্প হ'ল অ্যাপেন্ডারকে বিদ্রূপ করা এবং এই অ্যাপেন্ডারে লগ করা হয়েছে কিনা তা যাচাই করা। Log4j 1.2.x এবং মকিতো উদাহরণস্বরূপ:

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

public class MyTest {

    private final Appender appender = mock(Appender.class);
    private final Logger logger = Logger.getRootLogger();

    @Before
    public void setup() {
        logger.addAppender(appender);
    }

    @Test
    public void test() {
        // when
        Logger.getLogger(MyTest.class).info("Test");

        // then
        ArgumentCaptor<LoggingEvent> argument = ArgumentCaptor.forClass(LoggingEvent.class);
        verify(appender).doAppend(argument.capture());
        assertEquals(Level.INFO, argument.getValue().getLevel());
        assertEquals("Test", argument.getValue().getMessage());
        assertEquals("MyTest", argument.getValue().getLoggerName());
    }

    @After
    public void cleanup() {
        logger.removeAppender(appender);
    }
}

16

কার্যকরভাবে আপনি নির্ভরশীল শ্রেণীর একটি পার্শ্ব-প্রতিক্রিয়া পরীক্ষা করছেন। ইউনিট পরীক্ষার জন্য আপনাকে কেবল এটি যাচাই করতে হবে

logger.info()

সঠিক পরামিতি দিয়ে ডাকা হয়েছিল। অতএব লগার অনুকরণ করতে একটি মশকরা কাঠামো ব্যবহার করুন এবং এটি আপনাকে নিজের শ্রেণীর আচরণ পরীক্ষা করার অনুমতি দেবে।


3
আপনি কোনও বেসরকারী স্ট্যাটিক চূড়ান্ত ক্ষেত্রটিকে কীভাবে উপহাস করবেন, কোন সর্বাধিক লগারের সংজ্ঞা দেওয়া আছে? Powermockito? মজা করুন ..
স্টেফানো এল

স্টেফানো: সেই চূড়ান্ত ক্ষেত্রটি একরকমভাবে সূচনা হয়েছিল, আমি আসল জিনিসটির চেয়ে মকসকে ইনজেকশনের বিভিন্ন পন্থা দেখেছি। সম্ভবত প্রথম স্থানে পরীক্ষার জন্য কিছু স্তরের ডিজাইনের প্রয়োজন। blog.codecentric.de/en/2011/11/…
ডিজেএনএ

মেহেদী যেমন বলেছিলেন, সম্ভবত উপযুক্ত হ্যান্ডলার ব্যবহার করা যথেষ্ট হতে পারে,
ডিজেএনএ

11

বিদ্রূপ এখানে একটি বিকল্প, যদিও এটি শক্ত হবে, কারণ লোগারগুলি সাধারণত ব্যক্তিগত স্থিতিশীল চূড়ান্ত হয় - সুতরাং একটি মক লগার সেট করা কেকের টুকরো নয়, বা পরীক্ষার অধীনে শ্রেণীর পরিবর্তন প্রয়োজন।

আপনি একটি কাস্টম অ্যাপেন্ডার তৈরি করতে পারেন (বা যা যা বলা হোক না কেন) এবং এটি নিবন্ধভুক্ত করতে পারেন - হয় কেবলমাত্র পরীক্ষার জন্য একটি কনফিগারেশন ফাইল, বা রানটাইম (কোনও উপায়ে লগিংয়ের কাঠামোর উপর নির্ভরশীল)। এবং তারপরে আপনি সেই অ্যাপেন্ডারটি পেতে পারেন (হয় তবে স্ট্যাটিক্যালি, কনফিগারেশন ফাইলে ঘোষিত হলে বা তার বর্তমান রেফারেন্সের মাধ্যমে, যদি আপনি এটি রানটাইম প্লাগ করে থাকেন) এবং এর সামগ্রীগুলি যাচাই করতে পারেন।


10

@ রোনাল্ডব্লাশকের সমাধান থেকে অনুপ্রাণিত হয়ে আমি এটি নিয়ে এসেছি:

public class Log4JTester extends ExternalResource {
    TestAppender appender;

    @Override
    protected void before() {
        appender = new TestAppender();
        final Logger rootLogger = Logger.getRootLogger();
        rootLogger.addAppender(appender);
    }

    @Override
    protected void after() {
        final Logger rootLogger = Logger.getRootLogger();
        rootLogger.removeAppender(appender);
    }

    public void assertLogged(Matcher<String> matcher) {
        for(LoggingEvent event : appender.events) {
            if(matcher.matches(event.getMessage())) {
                return;
            }
        }
        fail("No event matches " + matcher);
    }

    private static class TestAppender extends AppenderSkeleton {

        List<LoggingEvent> events = new ArrayList<LoggingEvent>();

        @Override
        protected void append(LoggingEvent event) {
            events.add(event);
        }

        @Override
        public void close() {

        }

        @Override
        public boolean requiresLayout() {
            return false;
        }
    }

}

... যা আপনাকে এটি করতে দেয়:

@Rule public Log4JTester logTest = new Log4JTester();

@Test
public void testFoo() {
     user.setStatus(Status.PREMIUM);
     logTest.assertLogged(
        stringContains("Note added to account: premium customer"));
}

আপনি সম্ভবত এটি একটি স্মার্ট পদ্ধতিতে হামক্রেস্ট ব্যবহার করতে পারেন, তবে আমি এটি এ রেখেছি।


6

লগ 4 জ 2 এর জন্য সমাধানটি সামান্য আলাদা কারণ অ্যাপেন্ডারস্কেলটন আর উপলভ্য নয়। অতিরিক্ত হিসাবে, মকিতো, বা অনুরূপ লাইব্রেরি ব্যবহার করে একটি আর্গুমেন্টক্যাপ্টরের সাথে একটি অ্যাপেন্ডার তৈরি করতে যদি আপনি একাধিক লগিং বার্তাগুলির প্রত্যাশা করেন তবে কাজ করবে না কারণ একাধিক লগ বার্তাগুলির উপর মিউটেবললোগেন্ট পুনরায় ব্যবহৃত হয়েছে। লগ 4 জ 2 এর জন্য আমি যে সর্বোত্তম সমাধানটি পেয়েছি তা হ'ল:

private static MockedAppender mockedAppender;
private static Logger logger;

@Before
public void setup() {
    mockedAppender.message.clear();
}

/**
 * For some reason mvn test will not work if this is @Before, but in eclipse it works! As a
 * result, we use @BeforeClass.
 */
@BeforeClass
public static void setupClass() {
    mockedAppender = new MockedAppender();
    logger = (Logger)LogManager.getLogger(MatchingMetricsLogger.class);
    logger.addAppender(mockedAppender);
    logger.setLevel(Level.INFO);
}

@AfterClass
public static void teardown() {
    logger.removeAppender(mockedAppender);
}

@Test
public void test() {
    // do something that causes logs
    for (String e : mockedAppender.message) {
        // add asserts for the log messages
    }
}

private static class MockedAppender extends AbstractAppender {

    List<String> message = new ArrayList<>();

    protected MockedAppender() {
        super("MockedAppender", null, null);
    }

    @Override
    public void append(LogEvent event) {
        message.add(event.getMessage().getFormattedMessage());
    }
}

5

অন্যদের দ্বারা উল্লিখিত হিসাবে আপনি একটি উপহাসের কাঠামো ব্যবহার করতে পারেন। এটি কাজ করার জন্য আপনাকে আপনার শ্রেণিতে লগারটি প্রকাশ করতে হবে (যদিও আমি প্রস্তাব দিচ্ছি যে এটি জনসাধারণের সেটার তৈরির পরিবর্তে প্রাইভেট প্যাকেজ হিসাবে তৈরি করা উচিত)।

অন্য সমাধানটি হ'ল হাত দিয়ে একটি জাল লগার তৈরি করা। আপনাকে জাল লগার লিখতে হবে (আরও ফিক্সচার কোড) তবে এই ক্ষেত্রে আমি মশকরা ফ্রেমওয়ার্ক থেকে সংরক্ষিত কোডের বিরুদ্ধে পরীক্ষার বর্ধিত পাঠযোগ্যতা পছন্দ করব prefer

আমি এরকম কিছু করব:

class FakeLogger implements ILogger {
    public List<String> infos = new ArrayList<String>();
    public List<String> errors = new ArrayList<String>();

    public void info(String message) {
        infos.add(message);
    }

    public void error(String message) {
        errors.add(message);
    }
}

class TestMyClass {
    private MyClass myClass;        
    private FakeLogger logger;        

    @Before
    public void setUp() throws Exception {
        myClass = new MyClass();
        logger = new FakeLogger();
        myClass.logger = logger;
    }

    @Test
    public void testMyMethod() {
        myClass.myMethod(true);

        assertEquals(1, logger.infos.size());
    }
}

5

কি দারুন. আমি নিশ্চিত নই কেন এটি এত কঠিন ছিল। আমি খুঁজে পেয়েছি যে আমি উপরের কোডের নমুনাগুলির কোনওটিই ব্যবহার করতে পারিনি কারণ আমি লগ 4j2 এসএলএফ 4 জে ব্যবহার করছিলাম। এটি আমার সমাধান:

public class SpecialLogServiceTest {

  @Mock
  private Appender appender;

  @Captor
  private ArgumentCaptor<LogEvent> captor;

  @InjectMocks
  private SpecialLogService specialLogService;

  private LoggerConfig loggerConfig;

  @Before
  public void setUp() {
    // prepare the appender so Log4j likes it
    when(appender.getName()).thenReturn("MockAppender");
    when(appender.isStarted()).thenReturn(true);
    when(appender.isStopped()).thenReturn(false);

    final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    final Configuration config = ctx.getConfiguration();
    loggerConfig = config.getLoggerConfig("org.example.SpecialLogService");
    loggerConfig.addAppender(appender, AuditLogCRUDService.LEVEL_AUDIT, null);
  }

  @After
  public void tearDown() {
    loggerConfig.removeAppender("MockAppender");
  }

  @Test
  public void writeLog_shouldCreateCorrectLogMessage() throws Exception {
    SpecialLog specialLog = new SpecialLogBuilder().build();
    String expectedLog = "this is my log message";

    specialLogService.writeLog(specialLog);

    verify(appender).append(captor.capture());
    assertThat(captor.getAllValues().size(), is(1));
    assertThat(captor.getAllValues().get(0).getMessage().toString(), is(expectedLog));
  }
}

4

লগব্যাকের জন্য আমি যা করেছি তা এখানে।

আমি একটি পরীক্ষা প্রয়োগকারী ক্লাস তৈরি করেছি:

public class TestAppender extends AppenderBase<ILoggingEvent> {

    private Stack<ILoggingEvent> events = new Stack<ILoggingEvent>();

    @Override
    protected void append(ILoggingEvent event) {
        events.add(event);
    }

    public void clear() {
        events.clear();
    }

    public ILoggingEvent getLastEvent() {
        return events.pop();
    }
}

তারপরে আমার টেস্টঞ্জ ইউনিট পরীক্ষার ক্লাসের পিতামাতায় আমি একটি পদ্ধতি তৈরি করেছি:

protected TestAppender testAppender;

@BeforeClass
public void setupLogsForTesting() {
    Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    testAppender = (TestAppender)root.getAppender("TEST");
    if (testAppender != null) {
        testAppender.clear();
    }
}

আমার কাছে লগব্যাক-টেস্ট.এক্সএমএল ফাইল এসসিআর / পরীক্ষা / সংস্থানগুলিতে সংজ্ঞায়িত হয়েছে এবং আমি একটি পরীক্ষার অ্যাপেন্ডার যুক্ত করেছি:

<appender name="TEST" class="com.intuit.icn.TestAppender">
    <encoder>
        <pattern>%m%n</pattern>
    </encoder>
</appender>

এবং এই অ্যাপেন্ডারটিকে মূল সংযোজনকারীতে যুক্ত করেছেন:

<root>
    <level value="error" />
    <appender-ref ref="STDOUT" />
    <appender-ref ref="TEST" />
</root>

এখন আমার পরীক্ষার ক্লাসগুলিতে যা আমার পিতা-মাতার পরীক্ষার ক্লাস থেকে প্রসারিত আমি অ্যাপেন্ডার পেতে এবং শেষ বার্তাটি লগইন করতে পারি এবং বার্তাটি, স্তর, নিক্ষেপযোগ্য যাচাই করতে পারি।

ILoggingEvent lastEvent = testAppender.getLastEvent();
assertEquals(lastEvent.getMessage(), "...");
assertEquals(lastEvent.getLevel(), Level.WARN);
assertEquals(lastEvent.getThrowableProxy().getMessage(), "...");

আমি কোথায় দেখছি না যেখানে getappender পদ্ধতির সংজ্ঞা দেওয়া আছে?!?!
বায়োইনফরনেটিকস

getAppender একটি ch.qos.logback.classic.Logger উপর একটি পদ্ধতি
kfox

4

জুনিট 5 এর জন্য (বৃহস্পতি) স্প্রিংয়ের আউটপুটক্যাপচার এক্সটেনশন বেশ কার্যকর। এটি স্প্রিং বুট ২.২ থেকে পাওয়া যায় এবং এটি বসন্ত-বুট-পরীক্ষায় উপলব্ধ নিদর্শনগুলিতে পাওয়া যায়।

উদাহরণ (জাভাডোক থেকে নেওয়া):

@ExtendWith(OutputCaptureExtension.class)
class MyTest {
    @Test
    void test(CapturedOutput output) {
        System.out.println("ok");
        assertThat(output).contains("ok");
        System.err.println("error");
    }

    @AfterEach
    void after(CapturedOutput output) {
        assertThat(output.getOut()).contains("ok");
        assertThat(output.getErr()).contains("error");
    }
}

আমি বিশ্বাস করি লগের বিবৃতিগুলি এর বিপরীত getOut()বা getErr()
রাম

এটিই আমি উত্তরটি খুঁজছিলাম (যদিও প্রশ্নটি বসন্ত সম্পর্কিত নয়)
হেল্লে

3

আমার জন্য হিসাবে আপনি ব্যবহার করে আপনার পরীক্ষা প্রক্রিয়া সহজ করতে JUnitসঙ্গে Mockito। আমি এর জন্য নিম্নলিখিত সমাধান প্রস্তাব করছি:

import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.times;

@RunWith(MockitoJUnitRunner.class)
public class MyLogTest {
    private static final String FIRST_MESSAGE = "First message";
    private static final String SECOND_MESSAGE = "Second message";
    @Mock private Appender appender;
    @Captor private ArgumentCaptor<LoggingEvent> captor;
    @InjectMocks private MyLog;

    @Before
    public void setUp() {
        LogManager.getRootLogger().addAppender(appender);
    }

    @After
    public void tearDown() {
        LogManager.getRootLogger().removeAppender(appender);
    }

    @Test
    public void shouldLogExactlyTwoMessages() {
        testedClass.foo();

        then(appender).should(times(2)).doAppend(captor.capture());
        List<LoggingEvent> loggingEvents = captor.getAllValues();
        assertThat(loggingEvents).extracting("level", "renderedMessage").containsExactly(
                tuple(Level.INFO, FIRST_MESSAGE)
                tuple(Level.INFO, SECOND_MESSAGE)
        );
    }
}

এ কারণেই আমাদের কাছে বিভিন্ন বার্তার পরিমাণের সাথে পরীক্ষার জন্য দুর্দান্ত নমনীয়তা রয়েছে


1
প্রায় একই কোড ব্লকের পুনরাবৃত্তি না করতে যুক্ত করতে চান যে প্রায় 1to1 আমার জন্য লগ 4j2 এর জন্য কাজ করে। "Org.apache.logging.log4j.core" তে কেবল আমদানি পরিবর্তন করা, "org.apache.logging.log4j.core.Logger" এ লগ কাস্ট করুন, যুক্ত করুন when(appender.isStarted()).thenReturn(true); when(appender.getName()).thenReturn("Test Appender"); এবং লগিংএভেন্ট -> লগইভেন্ট
আলিয়াক্সেই ইয়াতাসৌ

3
Here is the sample code to mock log, irrespective of the version used for junit or sping, springboot.

import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import org.mockito.ArgumentMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.junit.Test;

import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class MyTest {
  private static Logger logger = LoggerFactory.getLogger(MyTest.class);

    @Test
    public void testSomething() {
    ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
    final Appender mockAppender = mock(Appender.class);
    when(mockAppender.getName()).thenReturn("MOCK");
    root.addAppender(mockAppender);

    //... do whatever you need to trigger the log

    verify(mockAppender).doAppend(argThat(new ArgumentMatcher() {
      @Override
      public boolean matches(final Object argument) {
        return ((LoggingEvent)argument).getFormattedMessage().contains("Hey this is the message I want to see");
      }
    }));
  }
}

1
এটি আমার পক্ষে কাজ করেছে। লাইন 'যখন (mockAppender.getName ()) then
মায়াঙ্ক রাঘব

1

লগ 4 জ 2 এর এপিআই কিছুটা আলাদা। এছাড়াও আপনি এটির async অ্যাপেন্ডার ব্যবহার করতে পারেন। আমি এটির জন্য একটি ল্যাচড অ্যাপেন্ডার তৈরি করেছি:

    public static class LatchedAppender extends AbstractAppender implements AutoCloseable {

    private final List<LogEvent> messages = new ArrayList<>();
    private final CountDownLatch latch;
    private final LoggerConfig loggerConfig;

    public LatchedAppender(Class<?> classThatLogs, int expectedMessages) {
        this(classThatLogs, null, null, expectedMessages);
    }
    public LatchedAppender(Class<?> classThatLogs, Filter filter, Layout<? extends Serializable> layout, int expectedMessages) {
        super(classThatLogs.getName()+"."+"LatchedAppender", filter, layout);
        latch = new CountDownLatch(expectedMessages);
        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        final Configuration config = ctx.getConfiguration();
        loggerConfig = config.getLoggerConfig(LogManager.getLogger(classThatLogs).getName());
        loggerConfig.addAppender(this, Level.ALL, ThresholdFilter.createFilter(Level.ALL, null, null));
        start();
    }

    @Override
    public void append(LogEvent event) {
        messages.add(event);
        latch.countDown();
    }

    public List<LogEvent> awaitMessages() throws InterruptedException {
        assertTrue(latch.await(10, TimeUnit.SECONDS));
        return messages;
    }

    @Override
    public void close() {
        stop();
        loggerConfig.removeAppender(this.getName());
    }
}

এটি এর মতো ব্যবহার করুন:

        try (LatchedAppender appender = new LatchedAppender(ClassUnderTest.class, 1)) {

        ClassUnderTest.methodThatLogs();
        List<LogEvent> events = appender.awaitMessages();
        assertEquals(1, events.size());
        //more assertions here

    }//appender removed

1

নোট করুন যে Log4J 2.x এ, পাবলিক ইন্টারফেসে এবং পদ্ধতিগুলি org.apache.logging.log4j.Loggerঅন্তর্ভুক্ত নয় ।setAppender()removeAppender()

তবে আপনি যদি খুব অভিনব কিছু না করে থাকেন তবে আপনি এটি প্রয়োগকারী ক্লাসে ফেলতে সক্ষম হবেন org.apache.logging.log4j.core.Logger, যা এই পদ্ধতিগুলি প্রকাশ করে।

এখানে একটি উদাহরণ Mockito এবং AssertJ :

// Import the implementation class rather than the API interface
import org.apache.logging.log4j.core.Logger;
// Cast logger to implementation class to get access to setAppender/removeAppender
Logger log = (Logger) LogManager.getLogger(MyClassUnderTest.class);

// Set up the mock appender, stubbing some methods Log4J needs internally
Appender appender = mock(Appender.class);
when(appender.getName()).thenReturn("Mock Appender");
when(appender.isStarted()).thenReturn(true);

log.addAppender(appender);
try {
    new MyClassUnderTest().doSomethingThatShouldLogAnError();
} finally {
    log.removeAppender(appender);
}

// Verify that we got an error with the expected message
ArgumentCaptor<LogEvent> logEventCaptor = ArgumentCaptor.forClass(LogEvent.class);
verify(appender).append(logEventCaptor.capture());
LogEvent logEvent = logEventCaptor.getValue();
assertThat(logEvent.getLevel()).isEqualTo(Level.ERROR);
assertThat(logEvent.getMessage().getFormattedMessage()).contains(expectedErrorMessage);

0

উল্লেখ করার মতো আরেকটি ধারণা, যদিও এটি একটি পুরানো বিষয়, আপনার লগার ইনজেক্ট করার জন্য একটি সিডিআই প্রযোজক তৈরি করছে যাতে বিদ্রূপ করা সহজ হয়ে যায়। (এবং এটি "সম্পূর্ণ লগার বিবৃতি" আর ঘোষণা না করার সুবিধাও দেয়, তবে এটি অফ-বিষয়)

উদাহরণ:

ইনজেকশনে লগার তৈরি করা:

public class CdiResources {
  @Produces @LoggerType
  public Logger createLogger(final InjectionPoint ip) {
      return Logger.getLogger(ip.getMember().getDeclaringClass());
  }
}

যোগ্যতা:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface LoggerType {
}

আপনার উত্পাদন কোডে লগার ব্যবহার:

public class ProductionCode {
    @Inject
    @LoggerType
    private Logger logger;

    public void logSomething() {
        logger.info("something");
    }
}

আপনার পরীক্ষার কোডে লগার পরীক্ষা করা (একটি সহজমক উদাহরণ দেওয়া):

@TestSubject
private ProductionCode productionCode = new ProductionCode();

@Mock
private Logger logger;

@Test
public void testTheLogger() {
   logger.info("something");
   replayAll();
   productionCode.logSomething();
}

0

Jmockit (1.21) ব্যবহার করে আমি এই সাধারণ পরীক্ষাটি লিখতে সক্ষম হয়েছি। পরীক্ষাটি নিশ্চিত করে যে কোনও নির্দিষ্ট ERROR বার্তা মাত্র একবার বলা হয়েছিল।

@Test
public void testErrorMessage() {
    final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger( MyConfig.class );

    new Expectations(logger) {{
        //make sure this error is happens just once.
        logger.error( "Something went wrong..." );
        times = 1;
    }};

    new MyTestObject().runSomethingWrong( "aaa" ); //SUT that eventually cause the error in the log.    
}

0

অ্যাপেন্ডারকে উপহাস করা লগ লাইনগুলি ক্যাপচারে সহায়তা করতে পারে। এর উপর নমুনা সন্ধান করুন: http://clearqa.blogspot.co.uk/2016/12/test-log-lines.html

// Fully working test at: https://github.com/njaiswal/logLineTester/blob/master/src/test/java/com/nj/Utils/UtilsTest.java

@Test
public void testUtilsLog() throws InterruptedException {

    Logger utilsLogger = (Logger) LoggerFactory.getLogger("com.nj.utils");

    final Appender mockAppender = mock(Appender.class);
    when(mockAppender.getName()).thenReturn("MOCK");
    utilsLogger.addAppender(mockAppender);

    final List<String> capturedLogs = Collections.synchronizedList(new ArrayList<>());
    final CountDownLatch latch = new CountDownLatch(3);

    //Capture logs
    doAnswer((invocation) -> {
        LoggingEvent loggingEvent = invocation.getArgumentAt(0, LoggingEvent.class);
        capturedLogs.add(loggingEvent.getFormattedMessage());
        latch.countDown();
        return null;
    }).when(mockAppender).doAppend(any());

    //Call method which will do logging to be tested
    Application.main(null);

    //Wait 5 seconds for latch to be true. That means 3 log lines were logged
    assertThat(latch.await(5L, TimeUnit.SECONDS), is(true));

    //Now assert the captured logs
    assertThat(capturedLogs, hasItem(containsString("One")));
    assertThat(capturedLogs, hasItem(containsString("Two")));
    assertThat(capturedLogs, hasItem(containsString("Three")));
}

0

নীচের কোডটি ব্যবহার করুন। আমি আমার বসন্তের একীকরণ পরীক্ষার জন্য একই কোডটি ব্যবহার করছি যেখানে আমি লগিংয়ের জন্য লগ ব্যাক ব্যবহার করছি। লগতে মুদ্রিত পাঠ্য সন্নিবেশ করার জন্য পদ্ধতি assertJobIs ਤਹਿ করে ব্যবহার করুন।

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;

private Logger rootLogger;
final Appender mockAppender = mock(Appender.class);

@Before
public void setUp() throws Exception {
    initMocks(this);
    when(mockAppender.getName()).thenReturn("MOCK");
    rootLogger = (Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
    rootLogger.addAppender(mockAppender);
}

private void assertJobIsScheduled(final String matcherText) {
    verify(mockAppender).doAppend(argThat(new ArgumentMatcher() {
        @Override
        public boolean matches(final Object argument) {
            return ((LoggingEvent)argument).getFormattedMessage().contains(matcherText);
        }
    }));
}


0

দুটি জিনিস রয়েছে যা আপনি যাচাই করার চেষ্টা করছেন।

  • যখন আমার প্রোগ্রামটির অপারেটরের আগ্রহের কোনও ইভেন্ট রয়েছে, তখন কি আমার প্রোগ্রামটি একটি উপযুক্ত লগিং অপারেশন সম্পাদন করে, যা অপারেটরটিকে সেই ইভেন্টটির অবহিত করতে পারে।
  • আমার প্রোগ্রামটি যখন লগিং অপারেশন সম্পাদন করে, তখন এটি উত্পন্ন লগ বার্তাটিতে সঠিক পাঠ্য রয়েছে কি?

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

  • এই পরীক্ষাগুলি মোটেই প্রোগ্রামের যুক্তি পরীক্ষা করে না, তারা কেবলমাত্র পরীক্ষা করে যে একটি সংস্থান (একটি স্ট্রিং) অন্য সংস্থানটির সমতুল্য।
  • পরীক্ষাগুলি ভঙ্গুর; এমনকি কোনও লগ ম্যাসেজের ফর্ম্যাট করতে একটি ছোটখাট ঝাঁকুনি আপনার পরীক্ষাগুলি ভেঙে দেয়।
  • পরীক্ষাগুলি আপনার লগিং ইন্টারফেসের আন্তর্জাতিকীকরণ (অনুবাদ) এর সাথে বেমানান The পরীক্ষাগুলি ধরে নিচ্ছে কেবলমাত্র একটি সম্ভাব্য বার্তা পাঠ্য রয়েছে, এবং এইভাবে কেবল একটি সম্ভাব্য মানব ভাষা।

মনে রাখবেন যে আপনার প্রোগ্রামের কোডটি রয়েছে (সম্ভবত কিছু ব্যবসায়িক যুক্তি বাস্তবায়ন করা) সরাসরি পাঠ্য লগিং ইন্টারফেসকে কল করা হ'ল দুর্বল নকশা (তবে দুর্ভাগ্যক্রমে খুব কম)। ব্যবসায়ের লজিকের জন্য দায়ী কোডটি কিছু লগিং নীতি এবং লগ বার্তাগুলির পাঠ্যও স্থির করে নিচ্ছে। এটি ব্যবহারকারীর ইন্টারফেস কোডের সাথে ব্যবসায়িক যুক্তিকে মিশ্রিত করে (হ্যাঁ, লগ বার্তাগুলি আপনার প্রোগ্রামের ইউজার ইন্টারফেসের অংশ) are এই জিনিসগুলি পৃথক করা উচিত।

তাই আমি প্রস্তাব দিচ্ছি যে ব্যবসায়ের যুক্তি সরাসরি লগ বার্তাগুলির পাঠ্য তৈরি করে না। পরিবর্তে এটি কোনও লগিং অবজেক্টে ডেলিগেট করুন।

  • লগিং অবজেক্টের শ্রেণীর জন্য একটি উপযুক্ত অভ্যন্তরীণ এপিআই সরবরাহ করা উচিত, যা আপনার ব্যবসায়িক অবজেক্টটি আপনার ডোমেন মডেলের অবজেক্টগুলি ব্যবহার করে ঘটেছে তা প্রকাশ করতে ব্যবহার করতে পারে, পাঠ্যের স্ট্রিংগুলি নয়।
  • আপনার লগিং ক্লাসের বাস্তবায়ন সেই ডোমেন অবজেক্টগুলির পাঠ্য উপস্থাপনা তৈরি করার জন্য এবং ইভেন্টের উপযুক্ত পাঠ্য বিবরণ দেওয়ার জন্য, তারপর সেই পাঠ্য বার্তাটি নিম্ন স্তরের লগিং ফ্রেমওয়ার্কে (যেমন JUL, log4j বা slf4j) ফরোয়ার্ড করার জন্য দায়ী।
  • আপনার ব্যবসার যুক্তি কেবলমাত্র আপনার লগার শ্রেণির অভ্যন্তরীণ এপিআইয়ের সঠিক পদ্ধতিগুলি কল করার জন্য, সঠিক ডোমেন অবজেক্টগুলি পাস করার জন্য ঘটেছে প্রকৃত ঘটনাগুলি বর্ণনা করার জন্য দায়ী।
  • তোমার কংক্রিট লগিং বর্গ implementsএকটি interface, যা অভ্যন্তরীণ API আপনার ব্যবসা লজিক ব্যবহার করতে পারেন বর্ণনা করা হয়েছে।
  • আপনার শ্রেণি (এস) যা ব্যবসায়িক যুক্তি প্রয়োগ করে এবং লগিং সম্পাদন করতে হবে তা প্রতিনিধি করার জন্য লগিং অবজেক্টের একটি রেফারেন্স রয়েছে। রেফারেন্সের ক্লাসটি বিমূর্ত interface
  • লগারের রেফারেন্স সেট আপ করতে নির্ভরতা ইনজেকশন ব্যবহার করুন।

তারপরে আপনি পরীক্ষা করতে পারেন যে আপনার ব্যবসায়ের লজিক ক্লাসগুলি মক লগার তৈরি করে যা আপনার অভ্যন্তরীণ লগিং এপিআই প্রয়োগ করে এবং আপনার পরীক্ষার সেট আপ পর্যায়ে নির্ভরতা ইনজেকশন ব্যবহার করে ইভেন্টগুলি সম্পর্কে সঠিকভাবে লগিং ইন্টারফেসকে বলে দেয়।

এটার মত:

 public class MyService {// The class we want to test
    private final MyLogger logger;

    public MyService(MyLogger logger) {
       this.logger = Objects.requireNonNull(logger);
    }

    public void performTwiddleOperation(Foo foo) {// The method we want to test
       ...// The business logic
       logger.performedTwiddleOperation(foo);
    }
 };

 public interface MyLogger {
    public void performedTwiddleOperation(Foo foo);
    ...
 };

 public final class MySl4jLogger: implements MyLogger {
    ...

    @Override
    public void performedTwiddleOperation(Foo foo) {
       logger.info("twiddled foo " + foo.getId());
    }
 }

 public final void MyProgram {
    public static void main(String[] argv) {
       ...
       MyLogger logger = new MySl4jLogger(...);
       MyService service = new MyService(logger);
       startService(service);// or whatever you must do
       ...
    }
 }

 public class MyServiceTest {
    ...

    static final class MyMockLogger: implements MyLogger {
       private Food.id id;
       private int nCallsPerformedTwiddleOperation;
       ...

       @Override
       public void performedTwiddleOperation(Foo foo) {
          id = foo.id;
          ++nCallsPerformedTwiddleOperation;
       }

       void assertCalledPerformedTwiddleOperation(Foo.id id) {
          assertEquals("Called performedTwiddleOperation", 1, nCallsPerformedTwiddleOperation);
          assertEquals("Called performedTwiddleOperation with correct ID", id, this.id);
       }
    };

    @Test
    public void testPerformTwiddleOperation_1() {
       // Setup
       MyMockLogger logger = new MyMockLogger();
       MyService service = new MyService(logger);
       Foo.Id id = new Foo.Id(...);
       Foo foo = new Foo(id, 1);

       // Execute
       service.performedTwiddleOperation(foo);

       // Verify
       ...
       logger.assertCalledPerformedTwiddleOperation(id);
    }
 }

0

আমি যা করতে চাইছি তা যদি দেখি যে কিছু স্ট্রিং লগ হয়েছে (সঠিক লগ স্টেটমেন্ট যা কেবল খুব ভঙ্গুর যাচাইয়ের বিপরীতে) StdOut কে একটি বাফারে পুনঃনির্দেশিত করা, একটি অন্তর্ভুক্ত করা, এবং তারপরে StdOut পুনরায় সেট করতে হবে:

PrintStream original = System.out;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
System.setOut(new PrintStream(buffer));

// Do something that logs

assertTrue(buffer.toString().contains(myMessage));
System.setOut(original);

1
আমি এটি দিয়ে চেষ্টা করেছি java.util.logging(যদিও আমি ব্যবহার করেছি System.setErr(new PrintStream(buffer));, কারণ এটি স্ট্যাডারে লগ হয়) তবে এটি কার্যকর হয় না (বাফার খালি থাকে)। আমি যদি System.err.println("foo")সরাসরি ব্যবহার করি তবে এটি কাজ করে, তাই আমি ধরে নিই যে লগিং সিস্টেম আউটপুট স্ট্রিমের নিজস্ব রেফারেন্স রাখে, যা এটি থেকে নেওয়া হয় System.err, সুতরাং আমার কলটি System.setErr(..)লগ আউটপুটে কোনও প্রভাব ফেলবে না, যেমন লগ সিস্টেম ইনডের পরে ঘটে।
হোইজুই

0

আমি log4j এর জন্য একই ধরণের প্রশ্নের উত্তর দিয়েছি কীভাবে-জুনিট-এর-একটি-সতর্কতা-লগ-সহ-লগ-করা হয়েছিল

এটি Log4j2 (2.11.2 দিয়ে পরীক্ষা করা) এবং জুনিট 5 এর সাথে আরও নতুন এবং উদাহরণ;

    package com.whatever.log;

    import org.apache.logging.log4j.Level;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.core.Logger;
    import org.apache.logging.log4j.core.*;
    import org.apache.logging.log4j.core.appender.AbstractAppender;
    import org.apache.logging.log4j.core.config.Configuration;
    import org.apache.logging.log4j.core.config.LoggerConfig;
    import org.apache.logging.log4j.core.config.plugins.Plugin;
    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    import org.apache.logging.log4j.core.config.plugins.PluginElement;
    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;

    import java.util.ArrayList;
    import java.util.List;
    import static org.junit.Assert.*;

class TestLogger {

    private TestAppender testAppender;
    private LoggerConfig loggerConfig;
    private final Logger logger = (Logger)
            LogManager.getLogger(ClassUnderTest.class);

    @Test
    @DisplayName("Test Log Junit5 and log4j2")
    void test() {
        ClassUnderTest.logMessage();
        final LogEvent loggingEvent = testAppender.events.get(0);
        //asset equals 1 because log level is info, change it to debug and
        //the test will fail
        assertTrue(testAppender.events.size()==1,"Unexpected empty log");
        assertEquals(Level.INFO,loggingEvent.getLevel(),"Unexpected log level");
        assertEquals(loggingEvent.getMessage().toString()
                ,"Hello Test","Unexpected log message");
    }

    @BeforeEach
    private void setup() {
        testAppender = new TestAppender("TestAppender", null);

        final LoggerContext context = logger.getContext();
        final Configuration configuration = context.getConfiguration();

        loggerConfig = configuration.getLoggerConfig(logger.getName());
        loggerConfig.setLevel(Level.INFO);
        loggerConfig.addAppender(testAppender,Level.INFO,null);
        testAppender.start();
        context.updateLoggers();
    }

    @AfterEach
    void after(){
        testAppender.stop();
        loggerConfig.removeAppender("TestAppender");
        final LoggerContext context = logger.getContext();
        context.updateLoggers();
    }

    @Plugin( name = "TestAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
    static class TestAppender extends AbstractAppender {

        List<LogEvent> events = new ArrayList();

        protected TestAppender(String name, Filter filter) {
            super(name, filter, null);
        }

        @PluginFactory
        public static TestAppender createAppender(
                @PluginAttribute("name") String name,
                @PluginElement("Filter") Filter filter) {
            return new TestAppender(name, filter);
        }

        @Override
        public void append(LogEvent event) {
            events.add(event);
        }
    }

    static class ClassUnderTest {
        private static final Logger LOGGER =  (Logger) LogManager.getLogger(ClassUnderTest.class);
        public static void logMessage(){
            LOGGER.info("Hello Test");
            LOGGER.debug("Hello Test");
        }
    }
}

নিম্নলিখিত maven নির্ভরতা ব্যবহার করে

 <dependency>
 <artifactId>log4j-core</artifactId>
  <packaging>jar</packaging>
  <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.5.0</version>
    <scope>test</scope>
</dependency>

আমি এটি চেষ্টা করেছিলাম এবং লগার লগারকনফিগ = কনফিগারেশন.সেটলোগারকনফিগ (লগার.সেটনাম ()) -এ সেটআপ পদ্ধতির অভ্যন্তরে একটি ত্রুটি পেয়েছি; ত্রুটিটি org.apache.logging.log4j.spi.LoggerContextShutdownEg सक्षम করা হয়েছে org.apache.logging.log4j.spi.LoggerContextSututdownEnable ক্লাস ফাইলটি অ্যাক্সেস করতে পারা যায় নি
কার্লোস

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

হ্যালো ওখানে হাইম। আমি লগব্যাক সমাধানটি প্রয়োগ করে শেষ করেছি ... তবে আমি মনে করি আপনি ঠিক বলেছেন, এটি কার্যকর করার জন্য আমাকে অন্য লগ 4 জে সংস্করণটি তৈরি করে একটি আমদানি পরিষ্কার করতে হয়েছিল।
কার্লোস পামমা

-1

আপনি যদি লগ 4j2 ব্যবহার করেন তবে https://www.dontpanicblog.co.uk/2018/04/29/test-log4j2-with-junit/ থেকে সমাধান আমাকে লগইন করার মঞ্জুরি দিয়েছে।

সমাধানটি এরকম হয়:

  • বাহ্যিক রিসোর্স বিধি হিসাবে লগ 4 জ অ্যাপেনডরকে সংজ্ঞায়িত করুন

    public class LogAppenderResource extends ExternalResource {
    
    private static final String APPENDER_NAME = "log4jRuleAppender";
    
    /**
     * Logged messages contains level and message only.
     * This allows us to test that level and message are set.
     */
    private static final String PATTERN = "%-5level %msg";
    
    private Logger logger;
    private Appender appender;
    private final CharArrayWriter outContent = new CharArrayWriter();
    
    public LogAppenderResource(org.apache.logging.log4j.Logger logger) {
        this.logger = (org.apache.logging.log4j.core.Logger)logger;
    }
    
    @Override
    protected void before() {
        StringLayout layout = PatternLayout.newBuilder().withPattern(PATTERN).build();
        appender = WriterAppender.newBuilder()
                .setTarget(outContent)
                .setLayout(layout)
                .setName(APPENDER_NAME).build();
        appender.start();
        logger.addAppender(appender);
    }
    
    @Override
    protected void after() {
        logger.removeAppender(appender);
    }
    
    public String getOutput() {
        return outContent.toString();
        }
    }
  • এমন একটি পরীক্ষা সংজ্ঞা দিন যা আপনার বাহ্যিক রিসোর্স নিয়ম ব্যবহার করে

    public class LoggingTextListenerTest {
    
        @Rule public LogAppenderResource appender = new LogAppenderResource(LogManager.getLogger(LoggingTextListener.class)); 
        private LoggingTextListener listener = new LoggingTextListener(); //     Class under test
    
        @Test
        public void startedEvent_isLogged() {
        listener.started();
        assertThat(appender.getOutput(), containsString("started"));
        }
    }

Src / পরীক্ষা / সংস্থানগুলির অংশ হিসাবে log4j2.xML রাখতে ভুলবেন না

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.