- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我阅读了很多有关单元测试、模拟以及所有这些内容的文章。我目前还在阅读 Steve Freeman 和 Nat Pryce 合着的“Growing Object-Oriented Software Guided by Tests”一书。
我开始理解很多东西,但遗漏了一个关键点,我试图在网上的任何地方找到答案,但我还不满意。
在下面的示例中,我有一个在线商店,它从第三方库接收消息,翻译这些消息,解释它们并最终在需要时将它们保存到数据库中。在一个具体案例中,我收到一条关于用户信用卡地址更改的消息,我想将该信息存储到数据库中。
结构如下:
src/
domain/
MessageTranslator.java
ShopEventListener.java
ShopHandler.java
model/
CreditCard.java
CreditCardBase.java
CreditCardBuilder.java
User.java
UserBase.java
UserBuilder.java
test/
MessageTranslatorTest.java
ShopHandlerTest.java
MessageTranslatorTest
public class MessageTranslatorTest {
@Test
public void notifiesCCAddressChangedWhenChangeCCAddressMessageReceived() throws Exception {
ShopEventListener listenerMock = mock(ShopEventListener.class);
MessageTranslator messageTranslator = new MessageTranslator(listenerMock);
messageTranslator.processMessage("action=changeCCAddress; firstname=John; lastname=Doe; address=foobar3");
verify(listenerMock).ccAddressChanged("John", "Doe", "foobar3");
}
}
MessageTranslator(现在很简单)
public class MessageTranslator {
private final ShopEventListener listener;
public MessageTranslator(ShopEventListener userEventListener) {
listener = userEventListener;
}
public void processMessage(String message) throws Exception {
String[] attributes = message.split(";");
listener.ccAddressChanged(attributes[1].split("=")[1].trim(), attributes[2].split("=")[1].trim(), attributes[3].split("=")[1].trim());
}
}
商店处理程序
public class ShopHandler implements ShopEventListener {
@Override
public void ccAddressChanged(String firstname, String lastname, String newAddress) throws Exception {
// find a user (especially userid) in the Database for given firstname and lastname
UserBase userBase = new UserBase();
User user = userBase.find(aUser().withFirstname(firstname).withLastname(lastname).build());
if (user == null) {
throw new Exception();
}
// find the matching CreditCard for the userid in the database
Integer userid = user.getUserid();
CreditCardBase ccBase = new CreditCardBase();
CreditCard cc = ccBase.find(aCreditCard().withUserid(userid).build());
if (cc == null) {
throw new Exception();
}
// change address locally and then write it back to the database
cc.setAddress(newAddress);
cc.persist();
}
}
ShopHandlerTest
public class ShopHandlerTest {
@Test
public void changesCCAddressWhenChangeCCAddressEventReceived() throws Exception {
ShopHandler shop = new ShopHandler();
shop.ccAddressChanged("John", "Doe", "foobar3");
// TODO: How to test the changes in inner object?
}
}
这是我经常犯错的地方。
抱歉发了这么长的帖子,但如果你能把我推向正确的方向,那就太棒了。如果您需要更多代码来理解上述内容,请告诉我。
最佳答案
Do I want to mock the helper classes UserBase and CreditCardBase to not perform any database queries but just return a prepared fake object?
看起来您的“辅助类”实际上是存储库/DAO。您通常希望独立于 DAO 测试您的业务逻辑,而不需要真正的数据库访问。所以是的,您可能应该模拟这些 DAO 并准备对它们的调用,因为它们会在现实中工作。在大多数情况下,准备好的假对象是可以的。您可能还想验证您的模拟 DAO 是否实际被调用。
Do I want to mock the persist-method to not write any real data to the database but maybe just test the parameters of the object to be persisted and have other (integration) tests test the database operations?
我觉得有点奇怪,您的业务实体中似乎有 persist
方法。通常 DAO 实现这种类型的方法。
是的,如果您测试业务逻辑,您也应该模拟对 DAO 的 persist
调用。如果您不这样做,您将对业务逻辑进行比应有的更繁重的测试。
是的,您也应该测试您的 DAO,但与业务逻辑分开。
If 1. and 2. will be answered with yes, then what am I actually testing here? Is it worth unittesting this unit then?
您正在测试您的业务逻辑。正是在您的 ccAddressChanged
方法中实现的。大致:
Does the structure make sense this way?
这和我习惯的不太一样。你似乎在实体中有数据访问逻辑,那么你也有这个“基础”帮助类......
If 1. and 2. will be answered with yes, then how do I mock the inner objects?
对于“内部对象”,您可能指的是这些辅助类。它们实际上更像是“帮助类”,它们是提供对数据库的访问的 DAO。您可以从外部传递或注入(inject)它们。基本上这是依赖注入(inject),你的业务逻辑依赖于这些 DAO 组件。如果您能够从外部传递它们,那么在您的测试中您可以模拟 DAO 并将模拟传递给您的业务服务。借助像 Spring 这样的 DI 框架,您将获得对此的框架支持。
这是使用 Spring 和 Mockito 对 ShopHandler
类进行测试的粗略草图:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ShopHandler.class})
public class ShopHandlerTest {
@Autowired
private ShopHandler sut;
@MockBean
private UserRepository userRepository;
@MockBean
private CreditCardRepository creditCardRepository;
@Test(expected = UserNotFoundException.class)
public void throwsUserNotFoundExceptionIfUserIsUnknown() {
when(userRepository.findUserByFirstNameAndLastName("Scott", "Tiger").thenReturn(null);
sut.ccAddressChanged("Scott", "Tiger", "Some Address");
}
@Test
public void successFullyUpdatesCreditCardAddress() {
when(userRepository.findUserByFirstNameAndLastName("Scott", "Tiger").thenReturn(new User("userId", ...));
when(creditCardRepository.findByUserId("userId")).thenReturn(new CreditCard(...));
ArgumentCaptor<CreditCard> creditCardCaptor = ArgumentCaptor.forClass(CreditCard.class);
verify(creditCardRepository).save(creditCardCaptor.capture());
sut.ccAddressChanged("Scott", "Tiger", "Some Address");
asserthThat(creditCardCaptor.getValue().getAddress()).isEqualTo("Some Address");
}
}
I feel like dependency injection is the wront approach here,
依赖注入(inject)在这里是一种非常明智的方法。
because first its no real dependency,
好吧,当然这些是真正的依赖关系。
but some helper classes,
您认为它从哪里结束成为“辅助类”并开始成为“真正的依赖项”?您所说的“帮助程序类”非常类似于 DAO,它们绝对是“真正的依赖项”。
second (and more important imo) the ShopHandler class could be flooded with dependencies, as it might need alot of different helper classes and model classes to perform all the different actions.
如果您需要执行所有这些操作并且需要所有这些依赖项来执行此操作,那么这就是现实。然而,问题是——您真的必须在一个业务服务中实现所有这些操作吗?不能把这个分成很多业务服务吗?然后你会得到更小的更集中的类,它们只需要几个依赖项。
关于java - 为什么以及如何模拟模型助手类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45960620/
有时我需要(为了让我的开发更快)在我的代码中对一些东西进行硬编码。这可能是凭据,或者可能只是一个允许我测试某些功能的 hack。由于很多原因,我从来不想将这段代码推送到主代码库甚至开发分支。一段时间以
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 2 年前。 Improve this qu
我经常发现自己从类中提取常见行为到只包含一组静态方法的帮助程序/实用程序类中。我经常想知道是否应该将这些类声明为抽象类,因为我真的想不出实例化这些类的正当理由? 将这样的类声明为抽象类的优点和缺点是什
如果我这样做: $obj = factory(Object::class)->make(); collect($obj); 我返回了一个类型的集合: Illuminate\Support\Collec
我有一个应用程序,我可以在其中列出 parent 和 child 。当我添加一个 child 时,我需要获得一个 parent 列表作为下拉列表显示。有没有类似 collection_select 的
我有渲染组件( source ),用于从 Controller 字段渲染组件/助手。它适用于 ember 1.9.1,但在更新到 ember 1.12.1 后,我发现 API 发生了变化。之后upda
我刚开始使用 Rails,还有很多东西需要学习,所以我可能会比平常更频繁地在 Stackoverflow 上询问初学者 Rails/Ruby 问题。 我只是想弄清楚 Helpers 在 Rails 中
我在 Web 上使用 VS Express 2012。我的项目是一个 MVC 4 项目。 我正在尝试创建一个助手来创建一个菜单项,该菜单项是带有标签的 png 图像。我几乎剪切并粘贴了这段代码: Ac
我正在尝试在我的 Vue 页面中映射我商店的状态变量: export default { data: () => ({ localData: []
我目前正在开发一个 Rails 插件,用于生成 iPhone 特定的 HTML 元标记。我尝试使用 ActionView::TestCase 进行单元测试,但不断收到相同的错误。请参阅下面的文件内容和
我正在努力解决一个与变量声明相关的非常基本的问题。我已经阅读了有关变量的所有内容,但我不知道我的问题是否与 1) 我如何声明变量或 2) 我如何设置变量的范围有关。 首先,我对 Meteor 中变量的
我想知道是否可以将参数传递给 Meteor Helper 并在 HTML 中插入返回对象的属性,而不仅仅是返回最终值。我有这样的东西: HTML: {{#each conversation}}
我正在尝试为我的 Ember 应用程序构建一个新的条件助手。值得一提的是,我正在使用使用 Handlebars 2.0 的 Ember 1.10.1,并且我无法升级它,如果能很好地解决这个版本的 Em
我最近从 Dreamweaver 迁移到 aptana,并尝试使 aptana 尽可能相似;) 已经做了很多更改,但我仍然找不到使代码字体变小的方法(在 Dreamweaver 中代码更清晰,因为字体
我有以下模板: {{#each helperOne "1" "2" }} Lorem upsom {{#each}} helper : template.tempName.h
我有这个简单的代码块,它位于我的一个模板上,但我想将其作为助手放置,以便我的所有 View 都可以访问它。 @hidden(field: Field) = { @defining(field)
使用正则表达式,我正在替换 **text in bold**至 text in bold在一个字符串中,然后显示 message使用 {{{message}}}在我的 EmberJS 模板上。问题是我
是否有任何非常有用和健壮的 C++ 网络库?和库来帮助他们更好地运行?诸如使用 << 时自动进行字节序转换之类的东西,阻止读取直到结构或 w/e 您的读取完全传输,有助于调试协议(protocol)的
模板 {{#each tags}} {{#isObject this}} Object {{else}}
我有返回 JSON 的函数: Template.mainmenu.menuitem = function() { var jsonObj = { items: [ { ur
我是一名优秀的程序员,十分优秀!