Spring in Action中的代码:
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnightTest {
@Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
BraveKnight knight = new BraveKnight(mockQuest);
knight.embarkOnQuest();
verify(mockQuest, times(1)).embark();
}
}
我理解依赖注入的使用,它允许我们在不修改依赖代码的情况下切换实现。
这本书说“编写单元测试非常困难......”。
但是,我无法理解如何在没有依赖注入的情况下进行单元测试非常困难!我的直觉拒绝合作!
您是否可以开始为“DamselRescuingKnight”类和任何其他更好的示例类(没有DI)编写junit / unit测试,以使我意识到DI使单元测试更容易的点/阶段?
答案 0 :(得分:3)
当您尝试测试git remote add REMOTE URL
时,上述示例中存在困难。假设您要测试那个(见下文)
DamselRescuingKnight
你怎么能确定knight.embarkOnQuest()确实做了什么?答案是你不能,因为你无法访问它在内部使用的任务实例。
现在,为了能够测试这样的类,您可以向Knight添加public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class DamselRescuingKnight Test {
@Test
public void knightShouldEmbarkOnQuest() {
DamselRescuingKnight knight = new DamselRescuingKnight ();
knight.embarkOnQuest();
// now what?
}
}
方法,然后还向Quest添加getQuest()
方法。
这也很公平地说,这个例子非常简单,因为骑士只调用没有参数的任务,而没有别的。如果骑士会与任务相互作用并从铁匠那里得到一些武器,那么你也会以某种方式允许其进入。你可以做所有的样板来完成它。但是假设,你将参数传递给铁匠 - 你如何确保传递的参数是正确的?或者你如何确保骑士在进入任务之前获得他的武器?
这是依赖注入来拯救的地方。你可以创建模拟(通过使用模拟框架,或通过实现自己的模拟),以便你可以验证你的骑士是否做了预期的事情。
答案 1 :(得分:1)
问题当然是 while($rows = $stmt->fetch(PDO::FETCH_ASSOC)){ ?>
<tr>
<td border="0" type="hidden" style="display:none;"><input type="hidden" name="hidden" value=<?php echo $rows['member_id']; ?></td>
<td class="center"><?php echo $rows['username']; ?></td>
<td class="center"><?php echo $rows['email']; ?></td>
<?PHP if($_SESSION['user_group'] == 63){
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username']; 'name="gp" value="system admin"' ?>
<?php echo ($rows['permission']== 31 )?'checked':'' ?>'</input> </td>' <?PHP ;
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username']; 'name="gp" value="admin"' ?>
<?php echo($rows['permission']== 15 )?'checked':'' ?> '</input> </td>' <?PHP ;
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username'];'name="gp" value="user"'
?><?php echo ($rows['permission']== 1 )?'checked':'' ?> '</input> </td>' <?PHP ; }
elseif($_SESSION['user_group'] == 31){
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username']; 'name="gp" value="admin"' ?>
<?php echo($rows['permission']== 15 )?'checked':'' ?> '</input> </td>' <?PHP ;
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username'];'name="gp" value="user"'
?><?php echo ($rows['permission']== 1 )?'checked':'' ?> '</input> </td>' <?PHP ; }
elseif($_SESSION['user_group'] == 15){
echo '<td class="center"><input type="radio" id='?><?php echo $rows['username'];'name="gp" value="user"'
?><?php echo ($rows['permission']== 1 )?'checked':'' ?> '</input> </td>' <?PHP ; }?>
<td class="center"><button name="update" type="update">submit</button></td>
</tr>
<?php
}
变量。您想以某种方式检查是否调用了quest
方法。如果不能用模拟实例替换它,这非常困难。
如果变量是embark()
而不是protected
,则测试用例可能会因为生活在同一个包中而覆盖它。
您还可以使用面向方面编程来替换变量。
但最简单的方法是,如果代码是从一开始就使用依赖注入编写的。
您想知道如何使用AOP。以下是一个AspectJ切入点的示例,您可以在单元测试中将private
实例替换为一个名为RescueDamselQuest
的模拟实例(如果我不能使语法完全正确,请为此道歉) ,自从我使用AspectJ以来已经有一段时间了:
MockRescueDamselQuest
这将捕获aspect MockRescueDamselQuestInstantiations {
RescueDamselQuest around (): call(RescueDamselQuest.new()) {
return new MockRescueDamselQuest();
}
}
的任何实例化(即调用RescueDamselQuest
)并返回new RescueDamselQuest()
对象。
考虑到这需要多少布线,我强烈建议使用依赖注入!
答案 2 :(得分:1)
当我在《 Spring in Action》中阅读本文时,这也使我感到困惑。阅读以上答案后,我想补充一点,当不使用DI时,Junit方法需要调用私有对象(可访问)的方法,并且该对象Quest是在DamselRescuingKnight的构造函数中创建的,因此embarkQuest()的测试用例可以不被写。相反,在使用DI时,您将外部化对象创建,而Junit方法可以创建该对象,以便可以对其进行访问,然后可以测试emabarkQuest(),而最终需要测试quest方法。