怎样编写测试类测试分支_编写干净的测试-被认为有害的新内容

怎样编写测试类测试分支

很难为干净的代码找到一个好的定义,因为我们每个人都有自己的单词clean的定义。 但是,有一个似乎是通用的定义:

简洁的代码易于阅读。

这可能会让您感到有些惊讶,但我认为该定义也适用于测试代码。 使测试尽可能具有可读性是我们的最大利益,因为:

  • 如果我们的测试易于阅读,那么很容易理解我们的代码是如何工作的。
  • 如果我们的测试易于阅读,那么如果测试失败(不使用调试器),很容易发现问题。

编写干净的测试并不难,但是需要大量的实践,这就是为什么如此多的开发人员为此苦苦挣扎的原因。

我也为此感到挣扎,这就是为什么我决定与您分享我的发现的原因。

这是我教程的第四部分,描述了我们如何编写干净的测试。 这次我们将学习为什么不使用new关键字在测试方法中创建对象。 我们还将学习如何用工厂方法和测试数据构建器替换new关键字。

新不是新黑

在本教程中,我们一直在重构单元测试,以确保当使用唯一的电子邮件地址和社交登录提供者创建新用户帐户时, RepositoryUserService类的registerNewUserAccount(RegistrationForm userAccountData)方法能够按预期工作。

RegistrationForm类是一个数据传输对象(DTO) ,我们的单元测试使用setter方法设置其属性值。 我们的单元测试的源代码如下所示(相关代码突出显示):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private static final String REGISTRATION_EMAIL_ADDRESS = "john.smith@gmail.com";private static final String REGISTRATION_FIRST_NAME = "John";private static final String REGISTRATION_LAST_NAME = "Smith";private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException       {RegistrationForm registration = new RegistrationForm();registration.setEmail(REGISTRATION_EMAIL_ADDRESS);registration.setFirstName(REGISTRATION_FIRST_NAME);registration.setLastName(REGISTRATION_LAST_NAME);registration.setSignInProvider(SOCIAL_SIGN_IN_PROVIDER);when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}
}

那么,有什么问题呢? 我们的单元测试中突出显示的部分很短,而且相对容易阅读。 我认为,此代码的最大问题是它是以数据为中心的。 它创建了一个新的RegistrationForm对象并设置了创建对象的属性值,但没有描述这些属性值的含义。

如果我们使用new关键字在测试方法中创建新对象,则由于以下原因,我们的测试将变得难以阅读:

  1. 读者必须知道所创建对象的不同状态。 例如,如果我们考虑示例,读者必须知道,如果我们创建一个新的RegistrationForm对象并设置emailfirstNamelastNamesignInProvider属性的属性值,则意味着该对象是一个注册,即通过使用社交登录提供商进行。
  2. 如果创建的对象具有许多属性,则创建该对象的代码会乱码我们测试的源代码。 我们应该记住,即使我们在测试中需要这些对象,我们也应该专注于描述被测试方法/功能的行为。

尽管不能完全消除这些缺点是不现实的,但我们应尽最大努力将其影响降到最低,并使我们的测试尽可能易于阅读。

让我们找出如何使用工厂方法来做到这一点。

使用工厂方法

当我们使用工厂方法创建新对象时,我们应该以这种方式命名工厂方法及其方法参数,以使我们的代码更易于读写。 让我们看一下两种不同的工厂方法,看看它们对我们的单元测试的可读性有什么样的影响。

这些工厂方法通常添加到对象母类中,因为它们通常对多个测试类有用。 但是,由于我想保持简单,因此将它们直接添加到测试类中。

第一个工厂方法的名称是newRegistrationViaSocialSignIn() ,并且没有方法参数。 在将此工厂方法添加到测试类之后,单元测试的源如下所示(相关部分已突出显示):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private static final String REGISTRATION_EMAIL_ADDRESS = "john.smith@gmail.com";private static final String REGISTRATION_FIRST_NAME = "John";private static final String REGISTRATION_LAST_NAME = "Smith";private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {RegistrationForm registration = newRegistrationViaSocialSignIn();when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}private RegistrationForm newRegistrationViaSocialSignIn() {RegistrationForm registration = new RegistrationForm();registration.setEmail(REGISTRATION_EMAIL_ADDRESS);registration.setFirstName(REGISTRATION_FIRST_NAME);registration.setLastName(REGISTRATION_LAST_NAME);registration.setSignInProvider(SOCIAL_SIGN_IN_PROVIDER);return registration;}
}

第一种工厂方法具有以下后果:

  • 我们测试方法的一部分,它创建了新的RegistrationForm对象,比以前干净得多,并且工厂方法的名称描述了所创建的RegistrationForm对象的状态。
  • 我们的模拟对象的配置更难以阅读,因为email属性的值在我们的工厂方法中被“隐藏”了。
  • 由于创建的RegistrationForm对象的属性值被“隐藏”在我们的工厂方法中,因此我们的断言更难以阅读。

如果使用对象母模式 ,则问题将更大,因为我们必须将相关的常量移至对象母类。

我认为可以说,尽管第一种工厂方法有其好处,但它也有严重的缺点。

让我们看看第二种工厂方法是否可以消除这些缺点。

第二个工厂方法的名称为newRegistrationViaSocialSignIn() ,并且它将电子邮件地址,名字,姓氏和提供程序中的社交符号作为方法参数。 在将此工厂方法添加到测试类之后,单元测试的源如下所示(相关部分已突出显示):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private static final String REGISTRATION_EMAIL_ADDRESS = "john.smith@gmail.com";private static final String REGISTRATION_FIRST_NAME = "John";private static final String REGISTRATION_LAST_NAME = "Smith";private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {RegistrationForm registration = newRegistrationViaSocialSignIn(REGISTRATION_EMAIL_ADDRESS,REGISTRATION_FIRST_NAME,REGISTRATION_LAST_NAME,SOCIAL_MEDIA_SERVICE);when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}private RegistrationForm newRegistrationViaSocialSignIn(String emailAddress, String firstName, String lastName, SocialMediaService signInProvider) {RegistrationForm registration = new RegistrationForm();registration.setEmail(emailAddress);registration.setFirstName(firstName);registration.setLastName(lastName);registration.setSignInProvider(signInProvider);return registration;}
}

第二种工厂方法具有以下后果:

  • 我们的测试方法的一部分(创建新的RegistrationForm对象)比使用第一个工厂方法的相同代码稍微有些混乱。 但是,它仍然比原始代码干净,因为factory方法的名称描述了创建对象的状态。
  • 似乎消除了第一个工厂方法的弊端,因为创建的对象的属性值未“隐藏”在工厂方法内部。

看起来很酷,对吧?

真的很容易想到天堂里一切都很好,但是事实并非如此。 尽管我们已经看到工厂方法可以使我们的测试更具可读性,但事实是,只有在满足以下条件时,它们才是一个不错的选择:

  1. 工厂方法没有太多的方法参数。 当方法参数的数量增加时,我们的测试将变得更加难以读写。 显而易见的问题是:工厂方法可以有多少个方法参数? 不幸的是,很难给出确切的答案,但是我认为,如果工厂方法只有少数方法参数,那么使用工厂方法是一个不错的选择。
  2. 测试数据没有太大的差异。 使用工厂方法的问题是单个工厂方法通常适用于一个用例。 如果我们需要支持N个用例,则需要N种工厂方法。 这是一个问题,因为随着时间的流逝,我们的工厂方法变得ated肿,混乱并且难以维护(尤其是如果使用对象母模式)。

让我们找出测试数据生成器是否可以解决其中一些问题。

使用测试数据构建器

测试数据构建器是使用构建器模式创建新对象的类。 Effective Java中描述的构建器模式有很多好处 ,但是我们的主要动机是提供一种流畅的API以创建测试中使用的对象。

我们可以按照以下步骤创建一个测试数据构建器类,该类创建新的RegistrationForm对象:

  1. 创建一个RegistrationFormBuilder类。
  2. RegistrationForm字段添加到创建的类。 该字段包含对创建对象的引用。
  3. 将默认构造函数添加到创建的类中,并通过创建新的RegistrationForm对象来实现它。
  4. 添加用于设置创建的RegistrationForm对象的属性值的方法。 每个方法都通过调用正确的setter方法来设置属性值,并返回对RegistrationFormBuilder对象的引用。 请记住,这些方法的方法名称可以建立或破坏我们的DSL
  5. 向所创建的类中添加一个build()方法,并通过返回所创建的RegistrationForm对象来实现它。

我们的测试数据构建器类的源代码如下所示:

public class RegistrationFormBuilder {private RegistrationForm registration;public RegistrationFormBuilder() {registration = new RegistrationForm();}public RegistrationFormBuilder email(String email) {registration.setEmail(email);return this;}public RegistrationFormBuilder firstName(String firstName) {registration.setFirstName(firstName);return this;}public RegistrationFormBuilder lastName(String lastName) {registration.setLastName(lastName);return this;}public RegistrationFormBuilder isSocialSignInViaSignInProvider(SocialMediaService signInProvider) {registration.setSignInProvider(signInProvider);return this;}public RegistrationForm build() {return registration;}
}

在修改了单元测试以使用新的测试数据构建器类之后,其源代码如下所示(相关部分已突出显示):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private static final String REGISTRATION_EMAIL_ADDRESS = "john.smith@gmail.com";private static final String REGISTRATION_FIRST_NAME = "John";private static final String REGISTRATION_LAST_NAME = "Smith";private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {RegistrationForm registration = new RegistrationFormBuilder().email(REGISTRATION_EMAIL_ADDRESS).firstName(REGISTRATION_FIRST_NAME).lastName(REGISTRATION_LAST_NAME).isSocialSignInViaSignInProvider(SOCIAL_SIGN_IN_PROVIDER).build();when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}
}

如我们所见,测试数据构建器具有以下优点:

  • 创建新的RegistrationForm对象的代码易于阅读和编写。 我非常喜欢流畅的API,并且我认为这段代码既优美又优雅。
  • 构建器模式可确保从我们的测试数据中发现的变化不再是问题,因为我们可以简单地将新方法添加到测试数据构建器类中。
  • 模拟对象和断言的配置易于阅读,因为常量在我们的测试方法中可见,并且DSL强调每个属性值的含义。

那么,我们应该对所有内容使用构建器模式吗?

没有!

仅在有意义时,才应使用测试数据构建器。 换句话说,我们应该在以下情况下使用它们:

  1. 我们设置了许多属性值。
  2. 我们的测试数据有很大的差异。

如果满足以下条件之一,则构建器模式是一个完美的选择。 原因是我们可以通过命名builder类的setter-like方法来创建特定于域的语言 。 即使我们将创建许多不同的对象并设置许多属性值,这也使我们的测试易于读写。

那是建造者木匠的力量。

如果您想了解有关流利API的更多信息,则应阅读以下文章:

  • 流利的界面
  • Java Fluent API设计器速成课程
  • 用Java构建流畅的API(内部DSL)

今天就这些。 让我们继续并总结从这篇博客文章中学到的知识。

摘要

我们了解了为什么使用new关键字在测试方法中创建对象不是一个好主意,并且我们学习了两种不同的方法来创建在测试中使用的对象。

更具体地说,这篇博客文章教会了我们三件事:

  • 通过使用new关键字在测试方法中创建所需的对象是一个坏主意,因为它会使我们的测试混乱且难以阅读。
  • 如果我们只需要设置少数几个属性值,而我们的测试数据没有太多变化,则应该使用工厂方法来创建所需的对象。
  • 如果必须设置很多属性值和/或我们的测试数据有很多差异,则应该使用测试数据生成器来创建所需的对象。

翻译自: https://www.javacodegeeks.com/2014/05/writing-clean-tests-new-considered-harmful.html

怎样编写测试类测试分支

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/341110.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不同字符串输入之间的区别

1 问题描述&#xff1a;scanf使用%c接受字符串 scanf使用%c接受字符串时无法识别回车符号 #include <iostream> int main() {char ch1,ch2;printf("Input for ch1:\n");scanf("%c",&ch1);printf("ch1%c\n",ch1);printf("Input …

第二章 数据结构(二)

文章目录Trie树存储并查集常规例题并查集维护多余信息堆性质存储基础操作downup操作例题Trie树 Tire&#xff1a;高效地存储和查找字符串集合的数据结构 存储 如果没有就创建。 对单词结尾进行标记&#xff0c;表示以当前节点结尾的地方存在一个单词 维护一个字符串集合&am…

Apache Camel 3只有2个月的路程

骆驼队正忙于为 Apache Camel3 。今天&#xff0c;第二个候选版本已构建并发布在暂存库中&#xff0c;供早期的适配器尝试 。 当我自己很忙的时候&#xff0c;我只想写一篇简短的博客文章&#xff0c;以使社区了解Apache Camel 3即将发布&#xff0c;我们希望它在今年年底&am…

第二章 数据结构(三)

文章目录哈希表存储结构拉链法&#xff1a;插入查询题目注意开放寻址法查找质数代码字符串哈希方式STL相关知识哈希表存储结构 整体结构 0~109->0~105 方法&#xff1a; x mod 105处理冲突 开放寻址法拉链法 拉链法&#xff1a; 思想&#xff1a;每个槽上拉一条链&…

Vaadin 10+作为CUBA UI的未来

从一开始&#xff0c;Vaadin就成为CUBA平台用户界面的基石和重要组成部分。 由于其创新的方法&#xff0c;它帮助CUBA将企业用户界面开发带到了一个非常有希望的&#xff08;如今是默认&#xff09;的WEB领域。 Vaadin最令人兴奋的部分之一是整个开发都是同构的&#xff0c;并且…

第二章 数据结构(一)

文章目录整体结构为什么用数组链表与邻接表单链表存储插入插入至头结点将x插入到下标为k的点后面删除遍历双链表初始化插入删除邻接表栈和队列栈队列单调栈单调队列KMP整体结构 链表与邻接表&#xff08;用数组模拟&#xff09;栈与队列&#xff08;用数组模拟&#xff09;kmp…

C++/C中默认初始值

1 全局变量 GCC编译器下各类型全局变量初始值 类型初始值数字的变量类型0boolfalsestring空字符串 2 局部变量 局部变量在没有赋值以前的值是不确定的&#xff0c;所以在声明局部变量的时候一定要初始化。特别是存在递归调用时。 举例&#xff1a; //例1 #include <iost…

unwind neo4j_Neo4j 2.1:传递节点ID与UNWIND

unwind neo4j当Neo4j 2.1发布时&#xff0c;我们将拥有UNWIND子句&#xff0c;该子句使处理事物集合变得更加容易。 在我的有关创建邻接矩阵的博客文章中&#xff0c;我们想要显示按字母顺序排列的前5个见面组中有多少人&#xff0c;然后检查其他各组中有多少人。 没有UNWIND…

第三章搜索与图论(一)

文章目录DFS与BFS区别DFS全排列n皇后BFS树和图的遍历树和图的存储数和图的遍历深度优先遍历宽度优先遍历图的宽搜应用框架DFS与BFS区别 DFS: 执着&#xff1a;一直走到头&#xff0c;回去的时候边回去边看能不能向下走 BFS: 稳重&#xff1a;每次只扩展一层&#xff0c;不会…

自动处理重复的代码

在本文中&#xff0c;我将描述如何使用Java :: Geci生成器Repeated以克服泛型不能为原始类型的Java语言不足。 该示例是对Apache Commons Lang库的建议扩展。 介绍 当您复制粘贴代码时&#xff0c;您做错了什么。 至少那是感知。 您必须创建更通用的代码结构&#xff0c;以便可…

第三章 搜索与图论(二)

文章目录最短路朴素Dijkstra算法堆优化版的Dijkstra算法Bellman-Ford算法SPFA算法求距离判负环Floyd最短路 并不区分有向图和无向图&#xff0c;因为无向图是一种特殊的有向图。直接用有向图的算法&#xff0c;解决无向图的问题。 常见情况可以分为两大类 在图论中&#xff0…

第三章 搜索与图论(三)

文章目录朴素版PrimKruskal算法染色法匈牙利算法朴素版Prim 给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出 impossible。给定一张边带权的无向图 G(V,E)&a…

JDK 14:记录,文本块等

今天的Mark Reinhold帖子“ 建议JEP针对JDK 14&#xff1a;305、343、359、366和368 ”提议针对JDK 14再针对五个JEP。 该组中有一些备受期待的功能&#xff0c;尽管建议除“预览”或“孵化”之外的所有功能&#xff1a; JEP 305 &#xff1a;instanceof的模式匹配&#xff08…

CDF 图的含义

CDF 图用于创建经验累积分布函数图。 使用 CDF 图可以确定等于或小于 x 轴上的给定值的数据的百分比。 例如&#xff0c;在该 CDF 图中&#xff0c;大约 34% 的数据小于总脂肪值 10 克。 参考链接 1. https://www.jmp.com/support/help/zh/14-2/ba-distribution-22.shtml

Typora表格中常用操作

快捷键行为Enter跳出表格Shift Enter表格内换行Alt Enter添加一行Alt 方向键向上/下移动该行

rome rss_RSS阅读器使用:ROME,Spring MVC,嵌入式Jetty

rome rss在这篇文章中&#xff0c;我将展示一些创建Spring Web应用程序的指南&#xff0c;这些应用程序使用Jetty并使用名为ROME的外部库运行RSS来运行它。 一般 我最近创建了一个示例Web应用程序&#xff0c;充当RSS阅读器。 我想检查ROME以阅读RSS。 我还想使用Spring容器和…

Ubuntu系统输入中文方式

我目前知道Ubuntu有两个还算好用的中文输入法&#xff1a; Fcitx&#xff1a;它是Linux世界开源的输入法框架&#xff0c;提供 Google PinYin、ShuangPin、SunPinYin、Wubi、ZhengMa、Hong Kong 和 TaiWan繁体等输入法。 1 安装Fcitx sudo apt install fcitx-pinyin fcit…

针对JDK 14提议的另外六个JEP

Mark Reinhold最近的消息宣布了六个新的“建议针对JDK 14的JEP ”&#xff1a; JEP 345 &#xff0c; JEP 361 &#xff0c; JEP 363 &#xff0c; JEP 364 &#xff0c; JEP 365和JEP 367 。 假设没有异议由11月7日提出&#xff0c;这些JEPs将有针对性地JDK 14与之前定位JEPs沿…

VMWare建立于W10的共享文件夹

一、共享文件夹建立 在虚拟机设置 -> 文件夹共享&#xff0c;选择总是启用&#xff0c;点击添加&#xff1a; 直接点击下一步&#xff1a; 选择原系统共享文件夹位置&#xff0c;并命名&#xff1a; 选择启用此共享&#xff0c;并继续&#xff1a; 二、VMtools安装 虚拟机…

Ubuntu中root用户和user用户的相互切换

Ubuntu是最近很流行的一款Linux系统&#xff0c;因为Ubuntu默认是不启动root用户&#xff0c;现在介绍如何进入root的方法。 &#xff08;1&#xff09;从user用户切换到root用户 不管是用图形模式登录Ubuntu&#xff0c;还是命令行模式登录&#xff0c;我们会发现缺省的用户…