C# 防止在单元测试上写入数据库-.NETMVC/EntityFramework

C# 防止在单元测试上写入数据库-.NETMVC/EntityFramework,c#,entity-framework,unit-testing,moq,C#,Entity Framework,Unit Testing,Moq,我正在尝试为使用实体框架的现有.NETMVC4.5Web应用程序编写单元测试。我想测试bool方法是否按预期返回true/false;但是,被测试的方法会写入数据库日志 不幸的是,这些测试引发以下异常: System.InvalidOperationException:在应用程序配置文件中找不到名为“xxxDbContext”的连接字符串 我不想修改数据库,我正在努力寻找一个如何在本例中模拟`DbContext`的示例 如何在不实际写入数据库的情况下仅测试布尔结果?在下面的示例中,Logger.

我正在尝试为使用实体框架的现有.NETMVC4.5Web应用程序编写单元测试。我想测试
bool
方法是否按预期返回
true
/
false
;但是,被测试的方法会写入数据库日志

不幸的是,这些测试引发以下异常:

System.InvalidOperationException:在应用程序配置文件中找不到名为“xxxDbContext”的连接字符串

我不想修改数据库,我正在努力寻找一个如何在本例中模拟`DbContext`的示例

如何在不实际写入数据库的情况下仅测试布尔结果?在下面的示例中,
Logger.Log()
向数据库添加了一行,我不希望在单元测试期间修改实际的数据库

下面是代码的简化示例:

试验方法 测试中的方法
谢谢大家!

您的
LocalFileCompare()
方法取决于
Logger
类(也称为“紧密耦合”)。由于
Logger
的实现会写入数据库,因此在调用
LocalFileCompare()
时无法避免写入数据库,除非删除依赖项。您可以通过使该方法依赖于一个接口来实现,让
Logger
类实现该接口,然后将其“注入”到
LocalFileCompare()
方法中

这将允许您通过简单地实现接口并使实现不写入数据库来轻松创建模拟记录器类

步骤1:创建
ILogger
界面

步骤2:更改
记录器
类以实现
ILogger

步骤3:更改
LocalFileCompare()
方法的签名以包含
ILogger
参数

步骤4:将
Logger
实例添加到对
LocalFileCompare()
方法的所有调用中

步骤5:使用模拟的
ILogger
实现更新测试

// Step 1
public interface ILogger
{
    void Log(string message);
}

// Step 2
public class Logger : ILogger
{
    void Log(string message)
    {
        // Implementation here
    }
}

// Step 3
public bool LocalFileCompare(FileInfo file1, FileInfo file2, ILogger logger)
{
    if (file1 == null || file2 == null)
    {
        logger.Log("LocalFileCompare: One or both files are null.");
        return false;
    }
    if (file1.FullName != file2.FullName)
    {
        logger.Log($"LocalFileCompare - file names don't match.");
        return false;
    }
    if (file1.Length != file2.Length)
    {
        logger.Log($"LocalFileCompare - file sizes don't match.");
        return false;
    }

    return true;
}

// Step 4
// Update your calls to LocalFileCompare()

// Step 5
// Put this somewhere in the Test project
public class MockLogger : ILogger
{
    void Log(string message)
    {
        Console.WriteLine(message);
    }
}

// In your test class
ILogger mockLogger;

// In your Test Setup method
mockLogger = new MockLogger();

[TestMethod]
public void LocalFileCompare_File2IsNull_ReturnsFalse()
{
    var t = new tManager(new tSet());
    FileInfo file1 = new FileInfo(@"C:\Temp\TempFile.txt");
    FileInfo file2 = null;

    var result = transferSet.LocalFileCompare(file1, file2, mockLogger);
    Assert.IsFalse(result);
}

如果您只是想要一个快速而肮脏的解决方案,而不必使用依赖项注入,那么您可以使用
预处理器

差不多

public void Log()
{
#if UnitTest
//Log to file
#else
//Log to db
#endif 
}

然后添加新的配置名称
UnitTest
。切换到该配置,然后转到项目属性->构建->条件编译符号->在

什么是
记录器
中添加
UnitTest
?插入标记的记录器或使用编译器宏为其编写不同的方法logger@Steve“注入”这种方法就是我在回答中解释的。你可以用Moq来模拟你的数据库-这很好->@DanielLoudon模拟数据库是为了集成测试。单元测试都应该在内存中运行,没有外部依赖关系。是的,如果这样做,你迟早会遇到麻烦:)@Bartosz这就是为什么它是一个快速而肮脏的解决方案。如果你只是在小规模上做这件事,那就太理想了。好吧,我不是说你没有警告OP:)这是对正确设计原则的肮脏攻击,应该是非法的:)
// Step 1
public interface ILogger
{
    void Log(string message);
}

// Step 2
public class Logger : ILogger
{
    void Log(string message)
    {
        // Implementation here
    }
}

// Step 3
public bool LocalFileCompare(FileInfo file1, FileInfo file2, ILogger logger)
{
    if (file1 == null || file2 == null)
    {
        logger.Log("LocalFileCompare: One or both files are null.");
        return false;
    }
    if (file1.FullName != file2.FullName)
    {
        logger.Log($"LocalFileCompare - file names don't match.");
        return false;
    }
    if (file1.Length != file2.Length)
    {
        logger.Log($"LocalFileCompare - file sizes don't match.");
        return false;
    }

    return true;
}

// Step 4
// Update your calls to LocalFileCompare()

// Step 5
// Put this somewhere in the Test project
public class MockLogger : ILogger
{
    void Log(string message)
    {
        Console.WriteLine(message);
    }
}

// In your test class
ILogger mockLogger;

// In your Test Setup method
mockLogger = new MockLogger();

[TestMethod]
public void LocalFileCompare_File2IsNull_ReturnsFalse()
{
    var t = new tManager(new tSet());
    FileInfo file1 = new FileInfo(@"C:\Temp\TempFile.txt");
    FileInfo file2 = null;

    var result = transferSet.LocalFileCompare(file1, file2, mockLogger);
    Assert.IsFalse(result);
}
public void Log()
{
#if UnitTest
//Log to file
#else
//Log to db
#endif 
}