国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++單元測(cè)試GoogleTest和GoogleMock十分鐘快速上手(gtest&gmock)

這篇具有很好參考價(jià)值的文章主要介紹了C++單元測(cè)試GoogleTest和GoogleMock十分鐘快速上手(gtest&gmock)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

C++單元測(cè)試GoogleTest和GoogleMock(gtest&gmock)

環(huán)境準(zhǔn)備

下載

git clone https://github.com/google/googletest.git
# 或者
wget https://github.com/google/googletest/releases/tag/release-1.11.0

安裝

cd googletest
cmake CMakeLists.txt 
make
sudo make install

重要文件

googletest
  • gtest/gtest.h
  • libgtest.a
  • libgtest_main.a

當(dāng)不想寫 main 函數(shù)的時(shí)候,可以直接引入 libgtest_main.a;

g++ sample.cc -o sample -lgtest -lgtest_main -lpthread 
g++ sample.cc -o sample -lgmock -lgmock_main -lpthread

否則

g++ sample.cc -o sample -lgtest -lpthread
googlemock
  • gmock/gmock.h
  • libgmock.a
  • libgmock_main.a

GoogleTest

一 .斷言

gtest中的斷言分成兩大類:

  1. ASSERT_\*系列:如果檢測(cè)失敗就直接退出當(dāng)前函數(shù)

  2. EXPECT_\*系列:如果檢測(cè)失敗發(fā)出提示,并繼續(xù)往下執(zhí)行

通常情況應(yīng)該首選使用EXPECT_,因?yàn)锳SSERT_在報(bào)告完錯(cuò)誤后不會(huì)進(jìn)行清理工作,有可能導(dǎo)致內(nèi)存泄露問(wèn)題。

gtest有很多類似的宏用來(lái)判斷數(shù)值的關(guān)系、判斷條件的真假、判斷字符串的關(guān)系。

條件判斷
ASSERT_TRUE(condition);  // 判斷條件是否為真
ASSERT_FALSE(condition); // 判斷條件是否為假

EXPECT_TRUE(condition);  // 判斷條件是否為真
EXPECT_FALSE(condition); // 判斷條件是否為假
數(shù)值比較
ASSERT_EQ(val1, val2); // 判斷是否相等
ASSERT_NE(val1, val2); // 判斷是否不相等
ASSERT_LT(val1, val2); // 判斷是否小于
ASSERT_LE(val1, val2); // 判斷是否小于等于
ASSERT_GT(val1, val2); // 判斷是否大于
ASSERT_GE(val1, val2); // 判斷是否大于等于

EXPECT_EQ(val1, val2); // 判斷是否相等
EXPECT_NE(val1, val2); // 判斷是否不相等
EXPECT_LT(val1, val2); // 判斷是否小于
EXPECT_LE(val1, val2); // 判斷是否小于等于
EXPECT_GT(val1, val2); // 判斷是否大于
EXPECT_GE(val1, val2); // 判斷是否大于等于
字符串比較
ASSERT_STREQ(str1,str2); // 判斷字符串是否相等
ASSERT_STRNE(str1,str2); // 判斷字符串是否不相等
ASSERT_STRCASEEQ(str1,str2); // 判斷字符串是否相等,忽視大小寫
ASSERT_STRCASENE(str1,str2); // 判斷字符串是否不相等,忽視大小寫

EXPECT_STREQ(str1,str2); // 判斷字符串是否相等
EXPECT_STRNE(str1,str2); // 判斷字符串是否不相等
EXPECT_STRCASEEQ(str1,str2); // 判斷字符串是否相等,忽視大小寫
EXPECT_STRCASENE(str1,str2); // 判斷字符串是否不相等,忽視大小寫
謂詞斷言

謂詞斷言能比 EXPECT_TRUE 提供更詳細(xì)的錯(cuò)誤消息;

EXPECT_PRED1(pred,val1);
EXPECT_PRED2(pred,val1,val2);
EXPECT_PRED3(pred,val1,val2,val3);
EXPECT_PRED4(pred,val1,val2,val3,val4);
EXPECT_PRED5(pred,val1,val2,val3,val4,val5);

ASSERT_PRED1(pred,val1);
ASSERT_PRED2(pred,val1,val2);
ASSERT_PRED3(pred,val1,val2,val3);
ASSERT_PRED4(pred,val1,val2,val3,val4);
ASSERT_PRED5(pred,val1,val2,val3,val4,val5);
// Returns true if m and n have no common divisors except 1. 
bool MutuallyPrime(int m, int n) { ... }
...
const int a = 3;
const int b = 4;
const int c = 10;
...
EXPECT_PRED2(MutuallyPrime, a, b);  // Succeeds
EXPECT_PRED2(MutuallyPrime, b, c);  // Fails

能得到錯(cuò)誤信息:

MutuallyPrime(b, c) is false, where 
b is 4
c is 10

二 .宏測(cè)試

如果自己編寫mian函數(shù),那么需要調(diào)用testing::InitGoogleTest函數(shù)進(jìn)行初始化然后調(diào)用RUN_ALL_TESTS(); 函數(shù)執(zhí)行所有的測(cè)試集

TEST

進(jìn)一步,為了更好的組織test cases,比如針對(duì)Factorial函數(shù),輸入是負(fù)數(shù)的cases為一組,輸入是0的case為一組,正數(shù)cases為一組。gtest提供了一個(gè)宏TEST(TestSuiteName, TestName),用于組織不同場(chǎng)景的cases,這個(gè)功能在gtest中稱為test suite

原型
#define TEST(test_suite_name,test_name)
代碼示例

TEST_F()宏的第一個(gè)參數(shù)(即test_suite_name的名稱)必須是測(cè)試裝置類的類名。

TEST(test_suite_name,test_name)
{
    //可以像普通函數(shù)一樣定義變量之類的行為。
    EXPECT_TRUE(condition);
    EXPECT_EQ(val1, val2);
    EXPECT_PRED1(pred,val1);
}
TEST_F

我們想讓多個(gè)Test使用同一套數(shù)據(jù)配置時(shí),就需要用到測(cè)試裝置,創(chuàng)建測(cè)試裝置的具體方法如下:

  • 派生一個(gè)繼承 ::testing::Test 的類,并將該類中的一些內(nèi)容聲明為 protected 類型,以便在子類中進(jìn)行訪問(wèn);
  • 根據(jù)實(shí)際情況,編寫默認(rèn)的構(gòu)造函數(shù)或SetUp()函數(shù),來(lái)為每個(gè) test 準(zhǔn)備所需內(nèi)容;
  • 根據(jù)實(shí)際情況,編寫默認(rèn)的析構(gòu)函數(shù)或TearDown()函數(shù),來(lái)釋放SetUp()中分配的資源;
  • 根據(jù)實(shí)際情況,定義 test 共享的子程序。

TEST_F()宏的第一個(gè)參數(shù)(即Test Case的名稱)必須是測(cè)試裝置類的類名。

它繼承testing::Test類,然后根據(jù)我們的需要實(shí)現(xiàn)下面這兩個(gè)虛函數(shù):

  • virtual void SetUp()類似于構(gòu)造函數(shù),總是在測(cè)試用例開始時(shí)被調(diào)用
  • virtual void TearDown()類似于析構(gòu)函數(shù),總是在測(cè)試用例結(jié)束后被調(diào)用

此外,testing::Test還提供了兩個(gè)static函數(shù):

  • static void SetUpTestSuite():在第一個(gè)TEST之前運(yùn)行
  • static void TearDownTestSuite():在最后一個(gè)TEST之后運(yùn)行
代碼示例
class QueueTestSmpl3 : public testing::Test { // 繼承了 testing::Test
protected:  

  static void SetUpTestSuite() {
    std::cout<<"run before first case..."<<std::endl;
  } 

  static void TearDownTestSuite() {
    std::cout<<"run after last case..."<<std::endl;
  }

  virtual void SetUp() override {
    std::cout<<"enter into SetUp()" <<std::endl;
    q1_.Enqueue(1);
    q2_.Enqueue(2);
    q2_.Enqueue(3);
  }

  virtual void TearDown() override {
    std::cout<<"exit from TearDown" <<std::endl;
  }

  static int Double(int n) {
    return 2*n;
  }

  void MapTester(const Queue<int> * q) {
    const Queue<int> * const new_q = q->Map(Double);

    ASSERT_EQ(q->Size(), new_q->Size());

    for (const QueueNode<int>*n1 = q->Head(), *n2 = new_q->Head();
         n1 != nullptr; n1 = n1->next(), n2 = n2->next()) {
      EXPECT_EQ(2 * n1->element(), n2->element());
    }

    delete new_q;
  }

  Queue<int> q0_;
  Queue<int> q1_;
  Queue<int> q2_;
};
測(cè)試集代碼
// in sample3_unittest.cc

// Tests the default c'tor.
TEST_F(QueueTestSmpl3, DefaultConstructor) {
  // !!! 在 TEST_F 中可以使用 QueueTestSmpl3 的成員變量、成員函數(shù) 
  EXPECT_EQ(0u, q0_.Size());
}

// Tests Dequeue().
TEST_F(QueueTestSmpl3, Dequeue) {
  int * n = q0_.Dequeue();
  EXPECT_TRUE(n == nullptr);

  n = q1_.Dequeue();
  ASSERT_TRUE(n != nullptr);
  EXPECT_EQ(1, *n);
  EXPECT_EQ(0u, q1_.Size());
  delete n;

  n = q2_.Dequeue();
  ASSERT_TRUE(n != nullptr);
  EXPECT_EQ(2, *n);
  EXPECT_EQ(1u, q2_.Size());
  delete n;
}

// Tests the Queue::Map() function.
TEST_F(QueueTestSmpl3, Map) {
  MapTester(&q0_);
  MapTester(&q1_);
  MapTester(&q2_);
}
運(yùn)行結(jié)果
% ./sample3_unittest
Running main() from /Users/self_study/Cpp/OpenSource/demo/include/googletest/googletest/samples/sample3_unittest.cc
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from QueueTestSmpl3
run before first case...    # 所有的test case 之前運(yùn)行
[ RUN      ] QueueTestSmpl3.DefaultConstructor
enter into SetUp()          # 每次都會(huì)運(yùn)行
exit from TearDown
[       OK ] QueueTestSmpl3.DefaultConstructor (0 ms)
[ RUN      ] QueueTestSmpl3.Dequeue
enter into SetUp()          # 每次都會(huì)運(yùn)行
exit from TearDown
[       OK ] QueueTestSmpl3.Dequeue (0 ms)
[ RUN      ] QueueTestSmpl3.Map
enter into SetUp()          # 每次都會(huì)運(yùn)行
exit from TearDown
[       OK ] QueueTestSmpl3.Map (0 ms)
run after last case...      # 所有test case結(jié)束之后運(yùn)行
[----------] 3 tests from QueueTestSmpl3 (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 3 tests.

GoogleMock

當(dāng)你寫一個(gè)原型或測(cè)試,往往不能完全的依賴真實(shí)對(duì)象。一個(gè) mock 對(duì)象實(shí)現(xiàn)與一個(gè)真實(shí)對(duì)象相同的接口,但讓你在運(yùn)行時(shí)指定它時(shí),如何使用?它應(yīng)該做什么?(哪些方法將被調(diào)用?什么順序?多少次?有什么參數(shù)?會(huì)返回什么?等)

可以模擬檢查它自己和調(diào)用者之間的交互;

mock 用于創(chuàng)建模擬類和使用它們;

  • 使用一些簡(jiǎn)單的宏描述你想要模擬的接口,他們將擴(kuò)展到你的 mock 類的實(shí)現(xiàn);
  • 創(chuàng)建一些模擬對(duì)象,并使用直觀的語(yǔ)法指定其期望和行為;
  • 練習(xí)使用模擬對(duì)象的代碼。 Google Mock會(huì)在出現(xiàn)任何違反期望的情況時(shí)立即處理。

注意

googlemock 依賴 googletest;調(diào)用 InitGoogleMock 時(shí)會(huì)自動(dòng)調(diào)用 InitGoogleTest ;

頭文件 #include “gmock/gmock.h”

什么時(shí)候使用?

  • 測(cè)試很慢,依賴于太多的庫(kù)或使用昂貴的資源;
  • 測(cè)試脆弱,使用的一些資源是不可靠的(例如網(wǎng)絡(luò));
  • 測(cè)試代碼如何處理失敗(例如,文件校驗(yàn)和錯(cuò)誤),但不容易造成;
  • 確保模塊以正確的方式與其他模塊交互,但是很難觀察到交互;因此你希望看到觀察行動(dòng)結(jié)束時(shí)的副作用;
  • 想模擬出復(fù)雜的依賴;

使用方法

我們假設(shè)一個(gè)支付場(chǎng)景邏輯開發(fā)業(yè)務(wù)。我們開發(fā)復(fù)雜的業(yè)務(wù)模塊,而團(tuán)隊(duì)其他成員開發(fā)用戶行為模塊。他們和我們約定了如下接口

class User {
public:
    User() {};
    ~User() {};
public:
    // 登錄
    virtual bool Login(const std::string& username, const std::string& password) = 0;
    // 支付
    virtual bool Pay(int money) = 0;
    // 是否登錄
    virtual bool Online() = 0;
};

我們的業(yè)務(wù)模塊要讓用戶登錄,并發(fā)起支付行為。于是我們的代碼如下

class Biz {
public:
    void SetUser(User* user) {
        _user = user;
    }

    std::string pay(const std::string& username, const std::string& password, int money) {
        std::string ret;
        if (!_user) {
            ret = "pointer is null.";
            return ret;
        }
        
        if (!_user->Online()) {
            ret = "logout status.";
            // 尚未登錄,要求登錄
            if (!_user->Login(username, password)) {
                // 登錄失敗
                ret += "login error.";
                return ret;
            } else {
                // 登錄成功
                ret += "login success.";
            }
        } else {
            // 已登錄
            ret = "login.status";
        }

        if (!_user->Pay(money)) {
            ret += "pay error.";
        } else {
            ret += "pay success.";
        }

        return ret;
    }

private:
    User* _user;
};

第一步我們需要Mock接口類

  • MOCK_METHOD0(FUNC, TYPE);第一個(gè)參數(shù)填寫函數(shù)名,第二個(gè)參數(shù)填寫函數(shù)類型
  • MOCK_METHOD()后面的數(shù)字表示需要幾個(gè)參數(shù)
  • const成員方法使用MOCK_CONST_METHOD系列
class TestUser : public User {
public:
    MOCK_METHOD2(Login, bool(const std::string&, const std::string&));
    MOCK_METHOD1(Pay, bool(int));
    MOCK_METHOD0(Online, bool());
};

第二步,我們就可以設(shè)計(jì)測(cè)試場(chǎng)景了。在設(shè)計(jì)場(chǎng)景之前,我們先看一些Gmock的方法

//   EXPECT_CALL(mock_object, Method(argument-matchers))
//       .With(multi-argument-matchers)
//       .Times(cardinality)
//       .InSequence(sequences)
//       .After(expectations)
//       .WillOnce(action)
//       .WillRepeatedly(action)
//       .RetiresOnSaturation();
//
// where all clauses are optional, and .InSequence()/.After()/
// .WillOnce() can appear any number of times.
  • EXPECT_CALL聲明一個(gè)調(diào)用期待,就是我們期待這個(gè)對(duì)象的這個(gè)方法按什么樣的邏輯去執(zhí)行。
  • mock_object是我們mock的對(duì)象,上例中就是TestUser的一個(gè)對(duì)象。
  • Method是mock對(duì)象中的mock方法,它的參數(shù)可以通過(guò)argument-matchers規(guī)則去匹配。
  • With是多個(gè)參數(shù)的匹配方式指定。
  • Times表示這個(gè)方法可以被執(zhí)行多少次。如果超過(guò)這個(gè)次數(shù),則按默認(rèn)值返回了。
  • InSequence用于指定函數(shù)執(zhí)行的順序。它是通過(guò)同一序列中聲明期待的順序確定的。
  • After方法用于指定某個(gè)方法只能在另一個(gè)方法之后執(zhí)行。
  • WillOnce表示執(zhí)行一次方法時(shí),將執(zhí)行其參數(shù)action的方法。一般我們使用Return方法,用于指定一次調(diào)用的輸出。
  • WillRepeatedly表示一直調(diào)用一個(gè)方法時(shí),將執(zhí)行其參數(shù)action的方法。需要注意下它和WillOnce的區(qū)別,WillOnce是一次,WillRepeatedly是一直。
  • RetiresOnSaturation用于保證期待調(diào)用不會(huì)被相同的函數(shù)的期待所覆蓋。

先舉一個(gè)例子,我們要求Online在第一調(diào)用時(shí)返回true,之后都返回false。Login一直返回false。Pay一直返回true。也就是說(shuō)用戶第一次支付前處于在線狀態(tài),并可以支付成功。而第二次將因?yàn)椴惶幱谠诰€狀態(tài),要觸發(fā)登錄行為,而登錄行為將失敗。我們看下這個(gè)邏輯該怎么寫

    {
        TestUser test_user;
        EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(true));
        EXPECT_CALL(test_user, Login(_,_)).WillRepeatedly(testing::Return(false));
        EXPECT_CALL(test_user, Pay(_)).WillRepeatedly(testing::Return(true));

        Biz biz;
        biz.SetUser(&test_user);
        std::string admin_ret = biz.pay("user", "", 1);
        admin_ret = biz.pay("user", "", 1);
    }

第4行的意思是Online在調(diào)用一次后返回true,之后的調(diào)用返回默認(rèn)的false。第5行意思是Login操作一直返回false,其中Login的參數(shù)是兩個(gè)下劃線(_),它是通配符,就是對(duì)任何輸入?yún)?shù)都按之后要求執(zhí)行。第6行意思是Pay操作總是返回true。那么我們?cè)诘?0行和第11行分別得到如下輸出

login status.pay success.
logout status.login error.

可以見得輸出符合我們的預(yù)期。

? 我們?cè)倏匆环N場(chǎng)景,這個(gè)場(chǎng)景我們使用了函數(shù)參數(shù)的過(guò)濾。比如我們不允許admin的用戶通過(guò)我們方法登錄并支付,則可以這么寫

    {
        TestUser test_user;
        EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));
        EXPECT_CALL(test_user, Login("admin",_)).WillRepeatedly(testing::Return(false));

        Biz biz;
        biz.SetUser(&test_user);
        std::string admin_ret = biz.pay("admin", "", 1);
    }

第3行表示,如果Login的第一個(gè)參數(shù)是admin,則總是返回false。于是07行返回是

logout status.login error.

那么如果不是admin的用戶登錄,則返回成功,這個(gè)案例要怎么寫呢?

    {
        TestUser test_user;
        EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));
        EXPECT_CALL(test_user, Login(StrNe("admin"),_)).WillRepeatedly(testing::Return(true));
        EXPECT_CALL(test_user, Pay(_)).WillRepeatedly(testing::Return(true));

        Biz biz;
        biz.SetUser(&test_user);
        std::string user_ret = biz.pay("user", "", 1);
    }

03行使用了StrNe的比較函數(shù),即Login的第一個(gè)參數(shù)不等于admin時(shí),總是返回true。08行的輸出是

logout status.login success.pay success.

我們?cè)倏匆粋€(gè)例子,我們要求非admin用戶登錄成功后,只能成功支付2次,之后的支付都失敗。這個(gè)案例可以這么寫

    {
        TestUser test_user;
        EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));
        EXPECT_CALL(test_user, Login(StrNe("admin"),_)).WillRepeatedly(testing::Return(true));
        EXPECT_CALL(test_user, Pay(_)).Times(5).WillOnce(testing::Return(true)).WillOnce(testing::Return(true)).WillRepeatedly(testing::Return(false));

        Biz biz;
        biz.SetUser(&test_user);
        std::string user_ret = biz.pay("user", "", 1);
        user_ret = biz.pay("user", "", 1);
        user_ret = biz.pay("user", "", 1);
    }

第4行我們使用Times函數(shù),它的參數(shù)5表示該函數(shù)期待被調(diào)用5次,從第6次的調(diào)用開始,返回默認(rèn)值。Times函數(shù)后面跟著兩個(gè)WillOnce,其行為都是返回true。這個(gè)可以解讀為第一次和第二次調(diào)用Pay方法時(shí),返回成功。最后的WillRepeatedly表示之后的對(duì)Pay的調(diào)用都返回false。我們看下執(zhí)行的結(jié)果

logout status.login success.pay success.
logout status.login success.pay success.
logout status.login success.pay error.

從結(jié)果上看,前兩次都支付成功了,而第三次失敗。符合我們的期待。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-742241.html

到了這里,關(guān)于C++單元測(cè)試GoogleTest和GoogleMock十分鐘快速上手(gtest&gmock)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 十分鐘掌握J(rèn)ava本地緩存

    —————————— Yesterday is history, tomorrow is a mystery, but today is a gift. That is why it’s called the present. —————————— 緩存是Java開發(fā)中經(jīng)常用到的組件,我們會(huì)使用緩存來(lái)存儲(chǔ)一些 不經(jīng)常改變 的 熱點(diǎn) 數(shù)據(jù),提高系統(tǒng)處理效率,其根本原因在于內(nèi)存和硬盤讀寫速度的

    2024年02月05日
    瀏覽(94)
  • Django入門,十分鐘學(xué)會(huì)登錄網(wǎng)頁(yè)

    我們假定你已經(jīng)閱讀了?安裝 Django。你能知道 Django 已被安裝,且安裝的是哪個(gè)版本,通過(guò)在命令提示行輸入命令 cmd黑窗口運(yùn)行,不懂cmd百度一下 如果這是你第一次使用 Django 的話,你需要一些初始化設(shè)置。也就是說(shuō),你需要用一些自動(dòng)生成的代碼配置一個(gè) Django?project?——

    2024年01月24日
    瀏覽(104)
  • 十分鐘python入門 正則表達(dá)式

    正則常見的三種功能,它們分別是:校驗(yàn)數(shù)據(jù)的有效性、查找符合要求的文本以及對(duì)文本進(jìn)行切割和替換等操作。 所謂元字符就是指那些在正則表達(dá)式中具有特殊意義的專用字符 元字符大致分成這幾類:表示單個(gè)特殊字符的,表示空白符的,表示某個(gè)范圍的,表示次數(shù)的量

    2024年02月13日
    瀏覽(92)
  • 十分鐘掌握 Vim 編輯器核心功能

    十分鐘掌握 Vim 編輯器核心功能

    ??相信不論是前端還是后臺(tái)多多少少都需要上到服務(wù)器上做一些操作,改改配置文件等,大多數(shù) Linux 服務(wù)器默認(rèn)都安裝了 Vim 文本編輯器,因此如果還不會(huì) Vim 的話,可能會(huì)被同事“恥笑”。 ??如果本文對(duì)你有所幫助,請(qǐng)點(diǎn)個(gè)?? 吧。 Vim是什么? Vim 是從 vi 發(fā)展出來(lái)的一個(gè)

    2024年02月16日
    瀏覽(98)
  • 十分鐘讀懂Stable Diffusion運(yùn)行原理

    十分鐘讀懂Stable Diffusion運(yùn)行原理

    AIGC 熱潮正猛烈地席卷開來(lái),可以說(shuō) Stable Diffusion 開源發(fā)布把 AI 圖像生成提高了全新高度,特別是 ControlNet 和 T2I-Adapter 控制模塊的提出進(jìn)一步提高生成可控性,也在逐漸改變一部分行業(yè)的生產(chǎn)模式。驚艷其出色表現(xiàn),也不禁好奇其背后技術(shù)。本文整理了一些學(xué)習(xí)過(guò)程中記錄的

    2024年02月09日
    瀏覽(86)
  • 十分鐘玩轉(zhuǎn)3D繪圖:WxGL完全手冊(cè)

    十分鐘玩轉(zhuǎn)3D繪圖:WxGL完全手冊(cè)

    WxGL是一個(gè)基于PyOpenGL的跨平臺(tái)三維數(shù)據(jù)快速可視化工具包,提供類似Matplotlib風(fēng)格的應(yīng)用方式。WxGL也可以集成到wxPython或PyQt6中實(shí)現(xiàn)更多的功能和控制。 WxGL提供了一套簡(jiǎn)潔易用、對(duì)用戶友好的API,將OpenGL的復(fù)雜概念封裝起來(lái),使得用戶可以更加專注于數(shù)據(jù)的處理,而無(wú)需在3

    2024年01月22日
    瀏覽(97)
  • 十分鐘實(shí)現(xiàn) Android Camera2 視頻錄制

    十分鐘實(shí)現(xiàn) Android Camera2 視頻錄制

    因?yàn)楣ぷ髦幸褂?Android Camera2 API ,但因?yàn)?Camera2 比較復(fù)雜,網(wǎng)上資料也比較亂,有一定入門門檻,所以花了幾天時(shí)間系統(tǒng)研究了下,并在 CSDN 上記錄了下,希望能幫助到更多的小伙伴。 上兩篇文章使用 Camera2 實(shí)現(xiàn)了相機(jī)預(yù)覽和拍照的功能,這篇文章我們接著上文,來(lái)實(shí)現(xiàn)

    2024年02月11日
    瀏覽(47)
  • 十分鐘實(shí)現(xiàn) Android Camera2 相機(jī)拍照

    十分鐘實(shí)現(xiàn) Android Camera2 相機(jī)拍照

    因?yàn)楣ぷ髦幸褂?Android Camera2 API ,但因?yàn)?Camera2 比較復(fù)雜,網(wǎng)上資料也比較亂,有一定入門門檻,所以花了幾天時(shí)間系統(tǒng)研究了下,并在 CSDN 上記錄了下,希望能幫助到更多的小伙伴。 上篇文章 我們使用 Camera2 實(shí)現(xiàn)了相機(jī)預(yù)覽的功能,這篇文章我們接著上文,來(lái)實(shí)現(xiàn) Cam

    2024年02月11日
    瀏覽(94)
  • 十分鐘實(shí)現(xiàn) Android Camera2 相機(jī)預(yù)覽

    十分鐘實(shí)現(xiàn) Android Camera2 相機(jī)預(yù)覽

    因?yàn)楣ぷ髦幸褂?Android Camera2 API ,但因?yàn)?Camera2 比較復(fù)雜,網(wǎng)上資料也比較亂,有一定入門門檻,所以花了幾天時(shí)間系統(tǒng)研究了下,并在 CSDN 上記錄了下,希望能幫助到更多的小伙伴。 Camera2 API 的包名是 android.hardware.camera2 ,是 Android 5.0 后推出的一套調(diào)用攝像頭設(shè)備的接口

    2024年02月13日
    瀏覽(42)
  • Nextcloud 使用教程, 十分鐘讓自己電腦成為私有云盤

    Nextcloud 使用教程, 十分鐘讓自己電腦成為私有云盤

    1、什么是Nextcloud? 假設(shè)你想在校內(nèi)搭建一個(gè)私有云盤服務(wù),并且有以下的需求,那么Nextcloud,簡(jiǎn)稱NC是你的不二之選, 沒(méi)有資金的投入,但是有相應(yīng)的需求; 需要部署在私有云上;有多客戶端要求(iOS、Android、MAC、Windows) 安全可靠,長(zhǎng)期更新,有和現(xiàn)有系統(tǒng)(例如LDAP集成

    2024年02月11日
    瀏覽(95)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包