问题 如何使用静态方法(UnitOfWork case)moq静态类?


我有这些课程:

public static class UnitOfWorkSS 
{
  public static IUnitOfWork Begin()
  {
    return IoC.Resolve<IUnitOfWork>();
  }
}

public class PostService
{
  using (IUnitOfWork unitOfWork = UnitOfWorkSS.Begin())
  {
    //don't forget to sanitize html content
    htmlContent = _htmlSanitizer.Sanitize(htmlContent);

    IPost post = _factory.CreatePost(byUser, title, htmlContent);                    

    _postRepository.Add(post);

    unitOfWork.Commit();
  }
}

我怎么能模拟这些课程 UnitOfWorkSS 和 unitOfWork


12849
2017-11-26 03:51


起源



答案:


看起来你通过调用Begin()做的唯一事情是返回你为该特定接口配置的类: IUnitOfWork

你真的只需要确保你对Begin()的调用返回一个模拟实现 IUnitOfWork

您可以通过以下两种方式之一:

方案一  - 重构 UnitOfWorkSS 这样你就可以设置实例了 IUnitOfWork 被退回

public static class UnitOfWorkSS  
{
    private static IUnitOfWork _unitOfWork;
    public static IUnitOfWork UnitOfWork
    {
        set { _unitOfWork = value; }
        private get{ _unitOfWork ?? (_unitOfWork = IoC.Resolve<IUnitOfWork>()); }
    }

    public static IUnitOfWork Begin()  
    {  
        return UnitOfWork;
    }  
}  

[TestMethod]
public void DoStuff()
{
    var mockUnitOfWork = new Mock<IUnitOfWork>();
    UnitOfWorkSS.UnitOfWork = mockUnitOfWork.Object;

    //Do some setup and verify
}

方案二  - 只需注册一个模拟实例 IUnitOfWork 与您的IoC容器

private Mock<IUnitOfWork> _mockUnitOfWork;

[TestInitialize]
public void Init()
{
    _mockUnitOfWork = new Mock<IUnitOfWork>();

    //Making a lot of assumptions about your IoC here...
    IoC.Register<IUnitOfWork>(_mockUnitOfWork.Object);
}

[TestMethod]
public void DoStuff()
{
    _mockUnitOfWork.Setup( ... );

    //Do some verification
}

9
2017-11-26 04:23



对于我来说,选项2似乎更好,因为选项1只是为了使其可测试而将状态引入静态类 - 但是也许这就是所有OP都在寻找的。 - aaaaaa


答案:


看起来你通过调用Begin()做的唯一事情是返回你为该特定接口配置的类: IUnitOfWork

你真的只需要确保你对Begin()的调用返回一个模拟实现 IUnitOfWork

您可以通过以下两种方式之一:

方案一  - 重构 UnitOfWorkSS 这样你就可以设置实例了 IUnitOfWork 被退回

public static class UnitOfWorkSS  
{
    private static IUnitOfWork _unitOfWork;
    public static IUnitOfWork UnitOfWork
    {
        set { _unitOfWork = value; }
        private get{ _unitOfWork ?? (_unitOfWork = IoC.Resolve<IUnitOfWork>()); }
    }

    public static IUnitOfWork Begin()  
    {  
        return UnitOfWork;
    }  
}  

[TestMethod]
public void DoStuff()
{
    var mockUnitOfWork = new Mock<IUnitOfWork>();
    UnitOfWorkSS.UnitOfWork = mockUnitOfWork.Object;

    //Do some setup and verify
}

方案二  - 只需注册一个模拟实例 IUnitOfWork 与您的IoC容器

private Mock<IUnitOfWork> _mockUnitOfWork;

[TestInitialize]
public void Init()
{
    _mockUnitOfWork = new Mock<IUnitOfWork>();

    //Making a lot of assumptions about your IoC here...
    IoC.Register<IUnitOfWork>(_mockUnitOfWork.Object);
}

[TestMethod]
public void DoStuff()
{
    _mockUnitOfWork.Setup( ... );

    //Do some verification
}

9
2017-11-26 04:23



对于我来说,选项2似乎更好,因为选项1只是为了使其可测试而将状态引入静态类 - 但是也许这就是所有OP都在寻找的。 - aaaaaa


模拟IUnitOfWork并将其注册到容器中,以便可以解决它。


2
2017-11-26 04:22





据我所知,你不能模拟静态类或方法。


1
2017-11-26 03:57



是的,我意识到了。但问题是我需要伪造那个功能,有没有办法做到这一点? - Attilah
据我所知,你必须将你的工作单元重写为非静态的。 - Chris


我意识到这是一个非常古老的问题,但万一有人在这里结束......

最好的解决方案是像其他答案所说的设计变更。但是,如果这不可能,您可以使用Microsoft Fakes(替换Moles),或者,如果您不依赖于Visual Studio,则可以使用名为Smocks的库来提供帮助。

https://github.com/vanderkleij/Smocks


0
2017-11-20 15:50