【问题标题】:Nunit and web applicationsNunit 和 Web 应用程序
【发布时间】:2011-05-30 10:59:14
【问题描述】:

我开始用“(NUnit)”学习Unit testing。我知道这种类型的测试是用来测试“类”、“函数”和“这些函数之间的交互”。

就我而言,我开发“asp.net web 应用程序”。

  • 我如何使用这个测试来测试我的 页面(因为它被视为一个类 以及使用的方法)和顺序?,我有三层:

    1. 界面层(每个页面的.cs)。

    2. 数据访问层(每个实体的类)(DAL)。

    3. 数据库层(包含与数据库的连接、打开连接、关闭连接……等)。

    4. 业务层(有时进行计算或一些单独的逻辑)。

  • 如何测试连接数据库的方法?

  • 如何确保我的测试不浪费时间?。

【问题讨论】:

    标签: asp.net unit-testing testing nunit database-connection


    【解决方案1】:

    有单元测试和集成测试。单元测试是测试单个组件/类/方法/函数以及它们之间的交互,但只有一个真实对象(被测系统-SUT)和测试替身。测试替身可以分为存根和模拟。存根向 SUT 提供准备好的测试数据。这样您就可以将 SUT 与环境隔离。因此,您不必访问数据库、Web 或 wcf 服务等,并且每次都有相同的输入数据。模拟用于验证 SUT 是否按预期工作。 SUT 在模拟对象上调用方法,甚至不知道它不是真实对象。然后,您通过在模拟对象上断言来验证 SUT 是否有效。您可以手动编写存根和模拟,也可以使用许多模拟框架之一。其中之一是http://code.google.com/p/moq/

    如果您想测试与数据库的交互,那是集成测试,通常要困难得多。对于集成测试,您必须在众所周知的状态下设置外部资源。

    让我们来看看你的图层:

    1. 您将无法对其进行单元测试。页面是紧密耦合到 ASP.NET 运行时的。您应该尝试在代码中没有太多代码。只需从您的代码中调用一些对象并测试这些对象。您可以查看 MVC 设计模式。如果您必须测试您的页面,您应该查看http://watin.org/。它自动化您的互联网浏览器,点击页面上的按钮并验证该页面显示预期结果。

    2. 这是集成测试。您将数据放入数据库中,然后将其读回并比较结果。测试之后或测试之前您必须将测试数据库置于众所周知的状态,以便测试可重复。我的建议是在测试运行之前而不是在测试运行之后设置数据库。这样您就可以在测试失败后检查数据库中的内容。

    3. 我真的不知道这与第 1 点有何不同。 2.

    4. 这是单元测试。在测试中创建对象,调用它的方法并验证结果。

    第 2 点中介绍了如何测试连接到数据库的方法。 如何不浪费时间?这将伴随着经验而来。除了不要测试没有任何逻辑的属性之外,我没有一般性建议。

    有关单元测试的详细信息,请看这里:

    http://artofunittesting.com/

    http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530

    http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627/ref=sr_1_2?ie=UTF8&s=books&qid=1306787051&sr=1-2

    http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054/ref=sr_1_1?ie=UTF8&s=books&qid=1306787051&sr=1-1

    编辑:

    SUT、CUT - 被测系统或类。这就是你测试的。 测试双打 - 来自特技双打。他们在电影中制作危险场景,这样真正的演员就不必这样做了。同样在这里。测试替身替换测试中的真实对象,以便您可以将测试中的 SUT/CUT 与环境隔离。

    让我们看看这个类

    
    public class NotTestableParty
    {
        public bool ShouldStartPreparing()
        {
            if (DateTime.Now.Date == new DateTime(2011, 12, 31))
            {
                Console.WriteLine("Prepare for party!");
                return true;
            }
            Console.WriteLine("Party is not today");
            return false;
        }
    }
    

    你将如何测试这门课在新年前夜的表现是否正确?你必须在新年前夜这样做:)

    现在看看修改后的 Party 类 存根示例:

        public class Party
        {
            private IClock clock;
    
            public Party(IClock clock)
            {
                this.clock = clock;
            }
    
            public bool ShouldStartPreparing()
            {
                if (clock.IsNewYearsEve())
                {
                    Console.WriteLine("Prepare for party!");
                    return true;
                }
                Console.WriteLine("Party is not today");
                return false;
            }
        }
    
        public interface IClock
        {
            bool IsNewYearsEve();
        }
    
        public class AlwaysNewYearsEveClock : IClock
        {
            public bool IsNewYearsEve()
            {
                return true;
            }
        }
    

    测试中你可以把假时钟传给Party课

            var party = new Party(new AlwaysNewYearsEveClock());
            Assert.That(party.ShouldStartPreparing(), Is.True);
    

    现在你知道你的派对课在新年前夜是否有效。 AlwaysNewYearsEveClock 是一个存根。

    现在看看这个类:

        public class UntestableCalculator
        {
            private Logger log = new Logger();
    
            public decimal Divide(decimal x, decimal y)
            {
                if (y == 0m)
                {
                    log.Log("Don't divide by 0");
                }
    
                return x / y;
            }
        }
    
        public class Logger
        {
            public void Log(string message)
            {
                // .. do some logging
            }
        }

    您将如何测试您的班级记录消息。取决于您记录它的位置您必须检查文件或数据库或其他地方。那不是单元测试,而是集成测试。为了单元测试你这样做。

        public class TestableCalculator
        {
            private ILogger log;
            public TestableCalculator(ILogger logger)
            {
                log = logger;
            }
            public decimal Divide(decimal x, decimal y)
            {
                if (y == 0m)
                {
                    log.Log("Don't divide by 0");
                }
                return x / y;
            }
        }
    
        public interface ILogger
        {
            void Log(string message);
        }
        public class FakeLogger : ILogger
        {
            public string LastLoggedMessage;
            public void Log(string message)
            {
                LastLoggedMessage = message;
            }
        }

    在测试中你可以

    var logger = new FakeLogger();
            var calculator = new TestableCalculator(logger);
            try
            {
                calculator.Divide(10, 0);
            }
            catch (DivideByZeroException ex)
            {
                Assert.That(logger.LastLoggedMessage, Is.EqualTo("Don't divide by 0"));
            }

    你在这里断言假记录器。假记录器是模拟对象。

    【讨论】:

    • 非常感谢Peri,有些概念不清楚,你能解释一下Test doubles,stubs ,mocks,SUT是什么意思。。“我不太清楚知道这与第 2 点有何不同。“数据库层直接使用数据库,数据访问层由每个实体(映射)的类组成,并使用数据库层访问数据并执行 CRUD 操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    相关资源
    最近更新 更多