简体   繁体   English

如何重构以避免使用Shim?

[英]How to refactor to avoid using a Shim?

I'm pretty new to Unit Testing and am exploring the Microsoft Fakes framework - primarily because it's free and it allows me to mock SharePoint objects easily with the Emulators package. 我对单元测试还很陌生,并且正在探索Microsoft Fakes框架-主要是因为它是免费的,它使我可以使用Emulators包轻松地模拟SharePoint对象。 I've seen various mentions on SO and elsewhere that Shims are evil and I more or less understand why. 我在SO和其他地方看到过各种各样的提述,认为Shims是邪恶的,而我或多或少都明白为什么。 What I don't get is how to avoid them in one specific case - in other words, "how should I refactor my code to avoid having to use shims?" 我没有得到的是如何在一种特定情况下避免使用它们,换句话说,“我应该如何重构代码以避免使用垫片?”

For the code in question, I have a JobProcessor object that has properties and methods, some of which are private as they should only be called from the public Execute method. 对于有问题的代码,我有一个JobProcessor对象,该对象具有属性和方法,其中一些是私有的,因为它们只能从公共Execute方法中调用。 I want to test that when Execute is called and there is a Job available that its Process method is called as I need to do some extra logging. 我想测试调用Execute时是否有一个Job可以调用其Process方法,因为我需要做一些额外的日志记录。

Here's the relevant code: 以下是相关代码:

//in system under test - JobProcessor.cs

private IJob CurrentJob { get; set; }

public void Execute()
{
   GetJobToProcess();  //stores Job in CurrentJob property if found
   if (ShouldProcessJob){
       CurrentJob.ProcessJob();
   }
}

I need to do some extra things if ProcessJob is called from a test, so I set up a Stub in my Test Method to do those extra things: 如果从测试中调用ProcessJob,我需要做一些额外的事情,因此我在测试方法中设置了一个Stub来做那些额外的事情:

StubIJob fakeJob = new StubIJob(){
    ProcessJob = () =>{
        //do my extra things here
    }

};

I'm testing the ProcessJob method itself elsewhere so I don't care that it doesn't do anything but my extra stuff here. 我正在其他地方测试ProcessJob方法,所以我不在乎它除了我在这里的多余工作外什么都不会做。 As I understand things, I now need to set up a Shim to have the private method GetJobsToProcess from JobProcessor (my system under test) return my fake job so that my stubbed method is called: 据我了解,我现在需要设置一个Shim,以使JobProcessor(我的被测系统)的私有方法GetJobsToProcess返回我的假作业,以便将我的存根方法称为:

processor = new JobProcessor();
ShimJobProcessor.AllInstances.GetJobToProcess = (@this) =>{
   var privateProcessor = new PrivateObject(processor);
   privateProcessor.SetProperty("CurrentJob", fakeJob);  //force my test Job to be processed so the Stub is used
};

In this case, how should I avoid using the Shim? 在这种情况下,如何避免使用Shim? Does it matter? 有关系吗?

Thanks. 谢谢。

This is a case where rather than using a shim or stub, I'd just make the method return a boolean to notify whether or not the inner call has happened. 在这种情况下,我只是使该方法返回一个布尔值以通知内部调用是否发生,而不是使用填充程序或存根。

The problem with using fakes there is that you're assuming that some method of some object is called, which the test should not know. 使用伪造品的问题在于,您假设调用了某个对象的某种方法,而测试不应该知道这种方法。 Tests should be dumb, and only see the outside of the code. 测试应该是愚蠢的,并且只能看到代码的外部。 Tests, like any other code, should not care how a value was reached, just that it is correct . 与其他任何代码一样,测试不关心值是如何达到的,只是它是正确的

However, your code has another issue as well. 但是,您的代码也有另一个问题。 You're getting some unknown object and using it within the same scope. 您将获得一些未知对象并在相同范围内使用它。 You should remove the call to GetJobToProccess from Execute. 您应该从Execute中删除对GetJobToProccess的调用。

It's the principle of Dependency Injection: a method should not spin up and hide it's dependencies; 这是依赖注入的原理:方法不应该旋转并隐藏其依赖; if it depends on an object, that object should be possible to change freely or be passed in. The exact implementation of the job should not matter to the execute method, and that, along with the naming, implies that you should not be getting that object and executing it in the same call. 如果它依赖于一个对象,则该对象应该可以自由更改或传递。该作业的确切实现与execute方法无关紧要,并且与命名一起暗示着您不应获取该对象。对象并在同一调用中执行它。

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

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