【发布时间】:2014-07-25 05:46:34
【问题描述】:
几天以来我一直在尝试测试指令,但找不到任何好的方法。
一点上下文:我们正在使用 Facebook 登录并在引导程序中获取朋友列表。此朋友列表存储在名为 UserConnection 的服务中。该服务有很多方法,但这里有 2 个重要的解决问题的方法
'use strict'
angular.module('AngularApp')
.service 'UserConnection', ['Configuration', 'localStorageService', 'Logger', '$location', '$q', '$timeout', '$rootScope', (Configuration, localStorageService, Logger, $location, $q, $timeout, $rootScope) ->
userConnection =
facebook : {}
friendsList : {}
services = {}
#
# Store the Facebook friends list
#
services.updateFBFriendsList = (_friendsList_) ->
lastInteractions = services.getLastUserInteractions()
friendsList = angular.copy(_friendsList_)
_.each(friendsList, (friend) ->
# Add locale to user
lang = friend.locale.split("_")[0]
if _.contains(userConnection.translation.availableLanguages, lang)
friend.lang = lang
else
friend.lang = userConnection.translation.defaultLanguage
delete friend.locale
# Add firstName
friend.firstname = friend.first_name
delete friend.first_name
# Add recentInteraction
interaction = _.indexOf(lastInteractions, friend.third_party_id)
friend.recentInteraction = if interaction >= 0 then interaction else false
)
userConnection.friendsList = _.indexBy(friendsList, 'third_party_id')
#
# Return every user friends, or one if an attribute is specified
#
services.getFBFriendsList = (specificAttribute = null) ->
if specificAttribute
return userConnection.friendsList[specificAttribute]
else
return userConnection.friendsList
return services
]
让我们回到我要测试的指令。我想测试函数updateLockers。在这个函数中,我调用 UserConnection 服务来检查好友列表中是否存在用户。
'use strict'
angular.module('AngularApp')
.directive 'lockers', ['Navigation', 'Backend', 'Tools', 'UserConnection',
(Navigation, Backend, Tools, UserConnection) ->
replace: true
restrict: 'A'
scope: true
templateUrl: 'views/directives/lockers.html'
link: ($scope, $elem, $attrs) ->
directiveId = "locker"
directiveReady = false
# $scope variables
$scope.lockers = []
$scope.active = false
$scope.open = false
$scope.delete = false
###################################
# Begin : Handling remote control #
###################################
# Close the menu
close = () ->
$scope.open = false
# If the menu was in deleting mode, we remove this
$scope.delete = false
# Open the menu
open = () ->
updateLockers()
$scope.open = true
# Activate the module
activate = () ->
$scope.active = true
# Desactivate the module
desactivate = () ->
$scope.active = false
close()
updateNavigation = () ->
if Navigation.navigationActiveStatus("navigation")
# If navigation should be activated
activate()
# If this module should be open
if Navigation.navigationOpeningStatus(directiveId)
open()
else
close()
# If this module should be refreshed
if Navigation.refreshNavigationStatus(directiveId)
updateLockers()
else
# Navigation must be desactivated
desactivate()
$scope.toggle = () ->
if $scope.open
Navigation.closeNavigation(directiveId)
else
Navigation.openNavigation(directiveId)
$scope.toggleDelete = () ->
$scope.delete = !$scope.delete
# If a component has updated the navigation status, we update
# the activation status
$scope.$on 'Navigation:statusUpdated', () ->
updateNavigation()
#################################
# End : Handling remote control #
#################################
# Test if there is no more locker in the list
$scope.isNotEmptyAndActive = () ->
return $scope.active and $scope.lockers.length > 0
$scope.buttonClick = (index, toDelete) ->
if toDelete
lockerToDelete = $scope.lockers[index]
Backend.transferStatusToCanceled(lockerToDelete.transfer_id).then(
(success) ->
$scope.lockers.splice(index, 1)
# Close the module is there is no more locker in the list
Navigation.closeNavigation(directiveId) unless $scope.isNotEmptyAndActive()
)
else
lockerToDownload = $scope.lockers[index]
UserConnection.redirectToTransferPage(lockerToDownload.sender, lockerToDownload.transfer_id, "internal")
# Call Backend server to get the last lockers list
updateLockers = (force = false) ->
if $scope.active or force
Backend.getLockerFiles().then(
(lockers) ->
$scope.lockers.length = 0
_.each lockers, (locker) ->
# We add the transfer only if the sender is still friend with the user
if UserConnection.getFBFriendsList(locker.sender)
# Add the complete sender details
locker.senderDetails = UserConnection.getFBFriendsList(locker.sender)
locker.humanReadableFileSize = Tools.humanReadableFileSize(locker.file_size)
locker.fileType = Tools.getFileType(locker.file_name)
locker.fileExt = Tools.getFileExtension(locker.file_name)
$scope.lockers.push locker
if not directiveReady
# Now the menu is ready to be displayed
Navigation.directiveReady(directiveId)
directiveReady = true
)
# We load lockers list when user is connected to Backend server
$scope.$on 'Facebook:userFriendsListLoaded', () ->
updateLockers(true)
]
当我测试函数 updateLockers 时,我们需要在 UserConnection 中拥有 Facebook 好友列表,为了获得这个列表,我需要登录 Facebook,登录我们的后端等等...
我显然想避免这种情况,所以我考虑为 UserConnection 服务创建一个 Mock。但是,这个服务非常庞大(我这里只放了 2 个方法),模拟它会是一项巨大的工作。
我不敢相信没有更好的解决方案。我错过了什么吗?有没有一种简单的方法可以避免嘲笑这项服务?也许通过单元测试策略是完全错误的......谢谢你的建议
【问题讨论】:
-
显示指令,你这里没有放相关代码。
-
@mpm 我添加了完整的代码,希望对您有所帮助。
-
如果您不想编写整个 UserConnection 服务的模拟实现,也许您可以使用像 in Jasmine 这样的间谍?我认为它通常不如单独的模拟实现好,因为您必须期待对间谍的每次调用,但如果您只需要监视几个调用,它可能比模拟整个服务更容易。
-
@andersschuller :使用 spyOn 和 andCallFake 完美地完成了这个把戏!谢谢你的提示
标签: angularjs unit-testing coffeescript angularjs-directive