日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何使用六邊形架構(gòu)測(cè)試存儲(chǔ)庫(kù)適配器

當(dāng)應(yīng)用六邊形架構(gòu)(端口和適配器)訪問數(shù)據(jù)庫(kù)等基礎(chǔ)設(shè)施元素時(shí),可以通過適配器的方式實(shí)現(xiàn)。適配器只是域定義的接口(端口)的實(shí)現(xiàn)。本文將提供同一存儲(chǔ)庫(kù)端口的兩個(gè)實(shí)現(xiàn),一個(gè)在內(nèi)存中,另一個(gè)基于JPA。其重點(diǎn)是如何使用相同的測(cè)試集測(cè)試這兩個(gè)實(shí)現(xiàn)。?

創(chuàng)新互聯(lián)建站主營(yíng)張家界網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都App定制開發(fā),張家界h5重慶小程序開發(fā)搭建,張家界網(wǎng)站營(yíng)銷推廣歡迎張家界等地區(qū)企業(yè)咨詢

場(chǎng)景

許多在企業(yè)場(chǎng)景中開發(fā)的軟件解決方案都有一些狀態(tài),需要保存在持久存儲(chǔ)設(shè)備中以供以后訪問。根據(jù)特定的功能性需求和非功能性需求,選擇正確的持久性解決方案可能很難,而且很可能需要一份架構(gòu)決策記錄(ADR),其中詳細(xì)說明了選擇的基本原理,包括替代方案和權(quán)衡。為了持久保持應(yīng)用程序狀態(tài),用戶需要參考CAP定理來做出最適當(dāng)?shù)臎Q策。 ?

這個(gè)決策過程不應(yīng)該延遲應(yīng)用程序域模型的設(shè)計(jì)和開發(fā)。工程團(tuán)隊(duì)?wèi)?yīng)該專注于交付(業(yè)務(wù))價(jià)值,而不是維護(hù)一堆DDL腳本和開發(fā)一個(gè)高度變化的數(shù)據(jù)庫(kù)模式,在幾周(或幾個(gè)月)之后,他們會(huì)意識(shí)到使用文檔數(shù)據(jù)庫(kù)而不是關(guān)系數(shù)據(jù)庫(kù)可能會(huì)更好。 ?

同樣,關(guān)注交付域值也會(huì)阻止工程團(tuán)隊(duì)基于過早采取的技術(shù)或基礎(chǔ)設(shè)施相關(guān)決策(例如在本例中是數(shù)據(jù)庫(kù)技術(shù))的約束而做出與域相關(guān)的決策。正如行業(yè)專家所說,其架構(gòu)應(yīng)該允許延遲框架決策(以及基礎(chǔ)設(shè)施決策)。 ?

推遲與基礎(chǔ)設(shè)施相關(guān)的決策

回到數(shù)據(jù)庫(kù)技術(shù)的例子,一種推遲基礎(chǔ)設(shè)施決策的方法是決定使用哪種數(shù)據(jù)庫(kù)技術(shù)應(yīng)使用,它將從存儲(chǔ)庫(kù)的簡(jiǎn)單內(nèi)存實(shí)現(xiàn)開始,其中域?qū)嶓w可以存儲(chǔ)在內(nèi)存中的列表中。這種方法加速了特性和領(lǐng)域用例的發(fā)現(xiàn)、設(shè)計(jì)和實(shí)現(xiàn),使利益相關(guān)者能夠快速反饋重要事項(xiàng):域值。?

現(xiàn)在,有人可能會(huì)想,“但是,我并沒有交付一個(gè)端到端工作的特性”,或者“我如何使用存儲(chǔ)庫(kù)的內(nèi)存適配器驗(yàn)證這一特性?”在這里,像六邊形架構(gòu)(也稱為端口和適配器)這樣的架構(gòu)模式和像域驅(qū)動(dòng)設(shè)計(jì)(DDD)這樣的方法(對(duì)于擁有干凈的架構(gòu)和最終干凈的代碼來說不是強(qiáng)制性的)開始發(fā)揮作用。 ?

六邊形架構(gòu)

許多應(yīng)用程序是按照經(jīng)典的三層架構(gòu)設(shè)計(jì)的:?

(1)演示/控制器 ?

(2)服務(wù)(業(yè)務(wù)邏輯) ?

(3)持久層 ?

這種架構(gòu)傾向于將域定義(例如,域?qū)嶓w和值對(duì)象)與表(例如,ORM實(shí)體)混合在一起,通常表示為簡(jiǎn)單的數(shù)據(jù)傳輸對(duì)象。如下圖所示:?

與其相反,在六邊形架構(gòu)中,實(shí)際的持久性相關(guān)類都是基于域模型定義的。?

通過使用存儲(chǔ)庫(kù)的端口 (它被定義為域模型的一部分),可以定義與底層技術(shù)無關(guān)的集成測(cè)試,它驗(yàn)證了對(duì)存儲(chǔ)庫(kù)的域期望。以下了解在用于管理學(xué)生的簡(jiǎn)單域模型中的代碼是什么樣子的。 ?

展示代碼

作為域的一部分,這個(gè)存儲(chǔ)庫(kù)端口看起來如何呢?它本質(zhì)上定義了域?qū)Υ鎯?chǔ)庫(kù)的期望,并根據(jù)域泛在語(yǔ)言定義了所有方法: ?

Java 
public interface StudentRepository {

Student save(Student student);
Optional retrieveStudentWithEmail(ContactInfo contactInfo);
Publisher saveReactive(Student student);

}

基于存儲(chǔ)庫(kù)端口規(guī)范,可以創(chuàng)建集成測(cè)試定義。該定義僅依賴于端口,并且不知道為持久化域狀態(tài)而做出的任何底層技術(shù)決策。這個(gè)測(cè)試類將有一個(gè)屬性作為驗(yàn)證期望的存儲(chǔ)庫(kù)接口(端口)的實(shí)例。以下顯示了這些測(cè)試的樣子?

Java 
public class StudentRepositoryTest {

StudentRepository studentRepository;

@Test
public void shouldCreateStudent() {
Student expected = randomNewStudent();
Student actual = studentRepository.save(expected);

assertAll("Create Student",
() -> assertEquals(0L, actual.getVersion()),
() -> assertEquals(expected.getStudentName(), actual.getStudentName()),
() -> assertNotNull(actual.getStudentId())
);
}

@Test
public void shouldUpdateExistingStudent() {
Student expected = randomExistingStudent();
Student actual = studentRepository.save(expected);
assertAll("Update Student",
() -> assertEquals(expected.getVersion()+1, actual.getVersion()),
() -> assertEquals(expected.getStudentName(), actual.getStudentName()),
() -> assertEquals(expected.getStudentId(), actual.getStudentId())
);
}
}

一旦存儲(chǔ)庫(kù)測(cè)試定義完成,就可以為內(nèi)存存儲(chǔ)庫(kù)創(chuàng)建一個(gè)測(cè)試運(yùn)行時(shí)(集成測(cè)試): ?

Java 
public class StudentRepositoryInMemoryIT extends StudentRepositoryTest {

@BeforeEach
public void setup() {
super.studentRepository = new StudentRepositoryInMemory();
}

}

或者使用Postgres對(duì)JPA進(jìn)行更詳細(xì)的集成測(cè)試: ?

Java 
@Testcontainers
@ContextConfiguration(classes = {PersistenceConfig.class})
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class StudentRepositoryJpaIT extends StudentRepositoryTest{

@Autowired
public StudentRepository studentRepository;

@Container
public static PostgreSQLContainer container = new PostgreSQLContainer("postgres:latest")
.withDatabaseName("students_db")
.withUsername("sa")
.withPassword("sa");


@DynamicPropertySource
public static void overrideProperties(DynamicPropertyRegistry registry){
registry.add("spring.datasource.url", container::getJdbcUrl);
registry.add("spring.datasource.username", container::getUsername);
registry.add("spring.datasource.password", container::getPassword);
registry.add("spring.datasource.driver-class-name", container::getDriverClassName);
}

@BeforeEach
public void setup() {
super.studentRepository = studentRepository;
}
}

兩個(gè)測(cè)試運(yùn)行時(shí)都擴(kuò)展了相同的測(cè)試定義,因此可以確定,當(dāng)從內(nèi)存適配器切換到最終的全功能JPA持久性時(shí),不會(huì)有任何測(cè)試受到影響,因?yàn)樗恍枰渲孟鄳?yīng)的測(cè)試運(yùn)行時(shí)。

這種方法將允許用戶在不依賴于框架的情況下定義存儲(chǔ)庫(kù)端口的測(cè)試,并在域定義更好、更穩(wěn)定,以及團(tuán)隊(duì)決定使用更好地滿足解決方案質(zhì)量屬性的數(shù)據(jù)庫(kù)技術(shù)時(shí)重用這些測(cè)試。?

項(xiàng)目的整體結(jié)構(gòu)如下圖所示:?

項(xiàng)目的結(jié)構(gòu)介紹:?

  • student-domain:域定義模塊,包括實(shí)體、值對(duì)象、域事件、端口等。這個(gè)模塊不依賴于框架,盡可能使用Java。 ?
  • student-application:目前,這個(gè)模塊沒有代碼,因?yàn)樗隽吮疚牡姆秶W裱呅渭軜?gòu),該模塊編排對(duì)域模型的調(diào)用,成為域用例的入口點(diǎn)。 ?
  • student-repository-test:這個(gè)模塊包含存儲(chǔ)庫(kù)測(cè)試定義,不依賴于框架,只驗(yàn)證所提供的存儲(chǔ)庫(kù)端口的期望。 ?
  • student-repository-inmemory:域定義的存儲(chǔ)庫(kù)端口的內(nèi)存實(shí)現(xiàn)。它還包含集成測(cè)試,該測(cè)試為學(xué)生存儲(chǔ)庫(kù)測(cè)試的測(cè)試定義提供了端口的內(nèi)存適配器。 ?
  • student-repository-JPA:域定義的存儲(chǔ)庫(kù)端口的JPA實(shí)現(xiàn)。它還包含集成測(cè)試,該測(cè)試為學(xué)生存儲(chǔ)庫(kù)測(cè)試的測(cè)試定義提供了端口的內(nèi)存適配器。這個(gè)集成測(cè)試設(shè)置有點(diǎn)復(fù)雜,因?yàn)樗鼘⒁粋€(gè)基本的Spring場(chǎng)景和一個(gè)Postgres容器一起啟動(dòng)。
  • student-shared-kernel:這個(gè)模塊不在本文討論范圍之內(nèi);它為設(shè)計(jì)項(xiàng)目的其余部分提供了一些實(shí)用程序類和接口。

結(jié)論

在項(xiàng)目中使用這種架構(gòu)風(fēng)格可以促進(jìn)域模型和基礎(chǔ)設(shè)施元素之間的良好分離,確保后者不會(huì)影響前者,同時(shí)促進(jìn)良好的代碼質(zhì)量(干凈的代碼)和高可維護(hù)性。 ?

原文標(biāo)題:??Testing Repository Adapters With Hexagonal Architecture??,作者:David Cano


分享題目:如何使用六邊形架構(gòu)測(cè)試存儲(chǔ)庫(kù)適配器
URL網(wǎng)址:http://www.dlmjj.cn/article/cddppes.html