在测试实现时,我采取的是一种常见的方法,还是我做错了?

时间:2013-10-14 12:07:36

标签: c# unit-testing

好的,我有以下模块,它从表中返回用户ID的列表,其中id与正则表达式匹配:

public sealed class UserIdListRetriever : IUserIdListRetriever
{
    private readonly EntityFrameworkClass _databaseConnection;

    public UserIdListRetriever(EntityFrameworkClass databaseConnection)
    {
        _databaseConnection = databaseConnection;
    }

    public IEnumerable<string> Retrieve()
    {
        var salesAgents = _databaseConnection
            .tblAccounts
            .Select(account => account.UserId)
            .Distinct();

        var regex = new Regex(@"(?<=\\)(.*?)(?=\:)");

        return (from agent in salesAgents
                .AsEnumerable()
                select regex.Match(agent)
                into match
                where match.Success
                select match.Value.ToUpper())
                .OrderBy(match => match);
    }
}

这是界面:

public interface IUserIdListRetriever
{
    IEnumerable<string> Retrieve();
}

我一直在读我应该测试行为,而不是实现,但我关心的是我的类是否返回一个准确的用户ID列表。

我可以创建一个IUserIdListRetriever的模拟实现,并且可能在我的单元测试中断言我得到一个非空的字符串的IEnumerable,但是它不会测试我的LINQ是否正确,或者是否或者不是我的正则表达式是正确的,不觉得有用。

我觉得好像这两件事在这里很重要(无论我的LINQ是否正确,以及我的正则表达式是否正确),我最终会得到这样的测试类:

using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
etc etc

namespace myNamespaceTests
{
    [TestClass]
    public class UserIdListRetrieverTests
    {
        [TestMethod]
        public void UserIdListRetrieverReturnsAccurateInformation()
        {
            var databaseConnection = 
                new EntityFrameworkClass("connection;string;");

            var userIdListRetriever = new UserIdListRetriever(databaseConnection );

            var userIds = userIdListRetriever.Retrieve();

            /*
             * I put a breakpoint here, 
             * and run the same query in SQL Management studio 
             * to make sure I have the same results
            */
             Assert.IsTrue(userIds.Any());
        }
    }
}

这感觉非常错误,但从我的角度来看,我发现这是最有用的,因为它仍然允许我快速测试(尽管不是那么快),这个模块正在做我想做的事。

我有很多像这样的模块,而且我的代码仍然是模块化和可测试的,但是当我花一些时间手动运行单元测试,逐步执行每个模块并对数据库运行查询时,我发现测试很有用手动验证我的数据检索模块给我的信息是我期望看到的。在此之后,我可以放心地说,我的代码库中的每个模块都按照我的意愿行事。

我不认识任何以这种方式工作的人,这通常是一个坏兆头(我错了,还是其他人都错了?)。有人可以更有知识地解释我在这里错误的地方并解释他们如何测试类似上面的类,以便他们可以快速运行测试并且这些测试是自动化的,但他们可以放心地说他们的每个模块都有预期的行为?

由于

2 个答案:

答案 0 :(得分:2)

这种方法导致集成测试而不是单元测试。如果在没有可用于数据库的连接的构建服务器上运行单元测试,该怎么办?

首先,如果你正在使用实际资源,你必须处于有效状态。这将是一个集成测试,而不是单元测试。

因此,如果您想测试数据库连接的完整性,那么您就是正确的。但是,如果您只是想测试您的过滤器逻辑。然后你必须将你的方法Retrieve()重构成两部分。

part i)返回从数据库返回的确切结果。

第ii部分:对结果测试过滤器操作。

这样您就可以模拟从DB返回的结果。然后测试filterning的方法,以确保在给定的DB结果上它正常工作。

e.g。

        public IEnumerable<string> Retrieve()
        {
            return _databaseConnection.tblAccounts.Select(account => account.UserId).Distinct();
        }

        public IEnumerable<string> GetMatchingItems(IEnumerable<string> salesAgents)
        {
            var regex = new Regex(@"(?<=\\)(.*?)(?=\:)");

            return (from agent in salesAgents
                    .AsEnumerable()
                    select regex.Match(agent)
                        into match
                        where match.Success
                        select match.Value.ToUpper())
                    .OrderBy(match => match);
        }

答案 1 :(得分:2)

我一般认为,如果它涉及数据库,则不是单元测试。话虽如此,我已经看了几年同样的问题,但是我无法为您提供更优雅的解决方案来测试您的数据检索语句。

我会注意到此代码不遵守单一责任原则 - 它从EF源检索数据,然后进一步过滤它。你可以做的是将这段代码分成两个单独的部分:一个用于检索列表,另一个用于检查匹配正则表达式的字符串列表。然后,您可以轻松设置单元测试以验证正则表达式是否按预期工作。