简体   繁体   English

将mock类注入单元测试方法的方法中

[英]Inject mock class into method to unit test method

I'm trying to unit test a method which has a dependency on another class. 我正在尝试对一个依赖于另一个类的方法进行单元测试。 The method calls a class method on that class, essentially this: 该方法在该类上调用一个类方法,基本上是这样的:

func myMethod() {

     //do stuff
     TheirClass.someClassMethod()

}

Using dependency injection technique, I would like to be able to replace "TheirClass" with a mock, but I can't figure out how to do this. 使用依赖注入技术,我希望能够用模拟替换“TheyClass”,但我无法弄清楚如何做到这一点。 Is there some way to pass in a mock class (not instance)? 有没有办法传入模拟 (不是实例)?

EDIT: Thanks for the responses. 编辑:感谢您的回复。 Perhaps I should have provided more detail. 也许我应该提供更多细节。 The class method I am trying to mock is in an open source library. 我试图模拟的类方法是在一个开源库中。

Below is my method. 以下是我的方法。 I am trying to test it, while mocking out the call to NXOAuth2Request.performMethod . 我试图测试它,同时NXOAuth2Request.performMethodNXOAuth2Request.performMethod的调用。 This class method issues a network call to get the authenticated user's info from our backend. 此类方法发出网络调用以从后端获取经过身份验证的用户的信息。 In the closure, I am saving this info to the global account store provided by the open source library, and posting notifications for success or failure. 在闭包中,我将此信息保存到开源库提供的全局帐户存储中,并发布成功或失败的通知。

func getUserProfileAndVerifyUserIsAuthenticated() {

    //this notification is fired when the refresh token has expired, and as a result, a new access token cannot be obtained
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "didFailToGetAccessTokenNotification", name: NXOAuth2AccountDidFailToGetAccessTokenNotification, object: nil)

    let accounts = self.accountStore.accountsWithAccountType(UserAuthenticationScheme.sharedInstance.accountType) as Array<NXOAuth2Account>
    if accounts.count > 0 {
        let account = accounts[0]

        let userInfoURL = UserAuthenticationScheme.sharedInstance.userInfoURL

        println("getUserProfileAndVerifyUserIsAuthenticated: calling to see if user token is still valid")
        NXOAuth2Request.performMethod("GET", onResource: userInfoURL, usingParameters: nil, withAccount: account, sendProgressHandler: nil, responseHandler: { (response, responseData, error) -> Void in

            if error != nil {
                println("User Info Error: %@", error.localizedDescription);
                NSNotificationCenter.defaultCenter().postNotificationName("UserCouldNotBeAuthenticated", object: self)
            }
            else if let data = responseData {
                var errorPointer: NSError?
                let userInfo = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &errorPointer) as NSDictionary

                println("Retrieved user info")
                account.userData = userInfo

                NSNotificationCenter.defaultCenter().postNotificationName("UserAuthenticated", object: self)
            }
            else {
                println("Unknown error retrieving user info")
                NSNotificationCenter.defaultCenter().postNotificationName("UserCouldNotBeAuthenticated", object: self)
            }
        })
    }
}

In Swift this is better done by passing a function. 在Swift中,通过传递函数可以做得更好。 There are many ways to approach this, but here is one: 有很多方法可以解决这个问题,但这里有一个方法:

func myMethod(completion: () -> Void = TheirClass.someClassMethod) {
    //do stuff
    completion()
}

Now you can pass a completion handler, while existing code will continue to use the default method. 现在您可以传递完成处理程序,而现有代码将继续使用默认方法。 Notice how you can refer to the function itself ( TheirClass.someClassMethod ). 请注意如何引用函数本身( TheirClass.someClassMethod )。 You don't have to wrap it up in a closure. 你不必将它包装在一个闭包中。

You may find it better to let the caller just pass this all the time rather than making it a default. 您可能会发现让调用者始终通过此操作而不是将其设置为默认值会更好。 That would make this class less bound to TheirClass , but either way is fine. 这会使这个类更少绑定到TheirClass ,但无论哪种方式都可以。

It's best to integrate this kind of loose coupling, design-for-testability into the code itself rather than coming up with clever ways to mock things. 最好将这种松散耦合,可测试性设计集成到代码本身中,而不是用巧妙的方式来模拟事物。 In fact, you should ask yourself if myMethod() should really be calling someClassMethod() at all. 实际上,你应该问问自己myMethod()是否真的应该调用someClassMethod() Maybe these things should be split up to make them more easily tested, and then tie them together at a higher level. 也许这些东西应该分开以使它们更容易测试,然后将它们连接在一起。 For instance, maybe myMethod should be returning something that you can then pass to someClassMethod() , so that there is no state you need to worry about. 例如,也许myMethod应该返回一些你可以传递给someClassMethod() ,这样就没有你需要担心的状态了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM