单元测试 之 NUnit和RhinoMocks

在dotnet环境中,我们通常使用NUnit和RhinoMocks来编写单元测试。

  • NUnit 简介


NUnit是.net平台上的一个单元测试框架,用来帮助开发人员方便的完成单元测试的编写。其主页为

http://www.nunit.org,目前最新版本为2.6.3.

可以通过以下链接来查看不同版本的使用文档

http://www.nunit.org/index.php?p=documentation

  • Rhino Mocks简介

Rhino Mocks是一个模拟对象创建和管理框架。使用它,开发人员可以方便地模拟并断言依赖对象被调用的情况。

下载地址:http://hibernatingrhinos.com/downloads/rhino-mocks/latest

  • 如何编写测试用例
  1. 创建一个测试工程,命名为{被测试工程}.UnitTest, 并添加NUnit和RhinoMocks引用。把项目属性中Application 面板中的Outputtype设置为Class Library

    对应的dll 分别nunit.framework.dll和Rhino.Mocks.dll

  2. 创建测试类,命名为{被测试类}Test,测试类的目录结构和命名空间保持和被测试类一致。
  3. 在测试类中引入命名空间NUnit.Framework和Rhino.Mocks

    using NUnit.Framework;
    using Rhino.Mocks;

  4. 在测试类的summary注解中,列出测试列表,并把测试类使用[TestFixture]来标注
  5. [TestFixture]
    class SchoonerStorageTest
    {
    }
  6. 针对测试列表来建立测试用例,并使用[Test]来标注,测试用例采用Test_{TestedMethod}_{测试点}_{预期结果}来命名,测试过程分三步走

    [Test]

    public void Test_{TestedMethod}_{测试点}_{预期结果}()

    {

    测试过程分三步:

    //准备测试数据

    //执行被测试方法

    //验证期望结果

    }

  • 单元测试中的NUnit


测试用例执行过程

    [TestFixture]
    public class TestFixtureSetUpAndTearDownTest
    {
        [TestFixtureSetUp]
        public void RunBeforeAllTests()
        {
            Console.WriteLine("TestFixtureSetUp");
        }
        [TestFixtureTearDown]
        public void RunAfterAllTests()
        {
            Console.WriteLine("TestFixtureTearDown");
        }
        [SetUp]
        public void RunBeforeEachTest()
        {
            Console.WriteLine("SetUp");
        }
        [TearDown]
        public void RunAfterEachTest()
        {
            Console.WriteLine("TearDown");
        }
        [Test]
        public void Test1()
        {
            Console.WriteLine("Test1");
        }
    }
  1. TestFixtureSetUp(这个测试类启动时被调用一次)
  2. SetUp(每个测试用例启动时被调用一次)
  3. Test(执行测试用例)
  4. TearDown(每个测试用例结束时被调用一次)
  5. TestFixtureTeardDown(这个测试类结束时被调用一次)

断言使用(Assertions)

有两种断言模型

经典模型(classic model)

相等断言(Assert.AreEqual, Assert.AreNotEqual...)

引用相等断言(Assert.AreSame, Assert.AreNotSame...)

比较断言(Assert.Greater, Assert.Less ...)

类型断言(Assert.IsInstanceOfType, Assert.IsAssignableFrom...)

条件断言 (Assert.True, Assert.False, Assert.IsNan, Assert.IsNull, Assert.IsEmpty)

Assert类中有用的方法(这些方法运行你对测试进程进行控制)

Assert.Pass:使测试用例成功

The Assert.Pass method allows you to immediately end the test, recording
it as successful. Since it causes an exception to be thrown, it is more
efficient to simply allow the test to return. However, Assert.Pass allows
you to record a message in the test result and may also make the test
easier to read in some situations. Additionally, like the other methods
on this page, it can be invoked from a nested method call with the
result of immediately terminating test execution.

Assert.Fail:使测试用例失败

The Assert.Fail method provides you with the ability to generate a failure based
on tests that are not encapsulated by the other methods. It is also useful in
developing your own project-specific assertions.

Assert.Ignore:忽略测试用例

The Assert.Ignore method provides you with the ability to dynamically cause a
test or suite to be ignored at runtime. It may be called in a test, setup or
fixture setup method. We recommend that you use this only in isolated cases.
The category facility is provided for more extensive inclusion or exclusion of
tests or you may elect to simply divide tests run on different occasions into
different assemblies.

Assert.Inconclusive:测试用例使用现有测试数据不能正常完成(不是太理解这个方法的应用场景)

The Assert.Inconclusive method indicates that the test could not be
  completed with the data available. It should be used in situations where
  another run with different data might run to completion, with either a
  success or failure outcome.

DirectoryAssert类

FileAssert类

CollectionAssert类

StringAssert类

基于约束的模型(constraint-based model)

可以自定义约束来实现比较复杂的断言

Assert.That(..)

属性使用(Attributes)

测试异常发生

[Test(Description = "If the Id or Name attribute is not found in xpath ‘StorageManagement/WritePolicy/CategoryConfig/CategoryList/Category‘, an exception will be thrown.")]
[ExpectedException(ExpectedException = typeof(ConfigException), MatchType = MessageMatch.Contains, ExpectedMessage = "Id, Name attributes are required")]
public void Test_LoadConfig_RequiredInfoNotFound_CategoryInWritePolicyCategoryList()
{
    string confileFile = GetTestFile("CategoryStorageConfig_RequiredInfoNotFound_CategoryInWritePolicyCategoryList.xml");
    categoryStorageConfig.LoadConfig(confileFile);
    Assert.Fail("Failure");
}

测试超时

        [Test,Timeout(10*1000)]
        public void Test_WriteAndGetOneData()
        {
            ...
        }

测试用例分类

        [Test,Timeout(10*1000)]
        [Category("FunctionTest")]
        public void Test_WriteAndGetMultipleData()
        {
            ....
        }
  • 单元测试中的RhinoMocks

创建桩对象

桩对象不参与验证过程,其作用是使代码可以顺畅地运行到完成或运行到你希望测试的点。

例子

        [Test]
        public void CreateStub_1()
        {
            MockRepository mocks = new MockRepository();
            IAnimal animal = mocks.Stub<IAnimal>();
            animal.Legs = 1;
            Assert.AreEqual(1, animal.Legs);
        }

创建模拟对象

模拟对象参与验证过程,其作用是为了检测对应的依赖对象是否被调用,以及调用的顺序是否正确等等

严格:

给模拟对象设定的期望必须被执行,没有设定的期望不能发生,否则调用Verify或VerifyAll时,会导致测试用例失败

例子

        [Test]
        public void CreateStrictMock_1()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.StrictMock<ICustomerService>();
            customerService.Expect(p => p.BuyBook(null));
            mocks.ReplayAll();
            customerService.BuyBook(null);
            mocks.VerifyAll();
        }
        [Test]
        public void CreateStrictMock_2()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.DynamicMock<ICustomerService>();
            using (mocks.Record())
            {
                customerService.Expect(p => p.BuyBook(null)).Repeat.Any();
            }
            customerService.BuyBook(null);
            customerService.BuyBook(null);
            customerService.BuyBook(null);
            mocks.VerifyAll();
        }
        [Test]
        public void CreateStrictMock_3()
        {
            ICustomerService customerService = MockRepository.GenerateStrictMock<ICustomerService>();
            customerService.Expect(p => p.BuyBook(null));
            customerService.Expect(p => p.BuyTicket(null));
            customerService.BuyBook(null);
            customerService.BuyTicket(null);
            customerService.VerifyAllExpectations();
        }
        [Test]
        public void CreateStrictMock_ShouldBeFail()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.StrictMock<ICustomerService>();
            using (mocks.Record())
            {
                customerService.Expect(p => p.BuyBook(null)).Repeat.Any();
            }
            customerService.BuyBook(null);
            customerService.BuyTicket(null);//BuyTicket is not recorded and it cannot be called.
            mocks.VerifyAll();
        }

非严格:

给模拟对象设定的期望必须被执行,没有设定的期望可以发生,否则调用Verify或VerifyAll时,会导致测试用例失败

例子

[Test]
        public void CreateDynamicMock_1()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.DynamicMock<ICustomerService>();
            customerService.Expect(p => p.BuyBook(null));
            mocks.ReplayAll();
            customerService.BuyBook(null);
            mocks.VerifyAll();
        }
        [Test]
        public void CreateDynamicMock_2()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.DynamicMock<ICustomerService>();
            using (mocks.Record())
            {
                customerService.Expect(p => p.BuyBook(null));
            }
            customerService.BuyBook(null);
            mocks.VerifyAll();
        }
        [Test]
        public void CreateDynamicMock_3()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customerService = mocks.DynamicMock<ICustomerService>();
            using (mocks.Record())
            {
                customerService.Expect(p => p.BuyBook(null)).Repeat.Any();
            }
            customerService.BuyBook(null);
            customerService.BuyTicket(null);//Even though BuyTicket is not recorded and it be called.
            mocks.VerifyAll();
        }
        [Test]
        public void CreateDynamicMock_4()
        {
            MockRepository mocks = new MockRepository();
            IAnimal animal = mocks.DynamicMock<IAnimal>();
            Expect.Call(animal.Legs).PropertyBehavior();
            animal.Legs = 1;
            Assert.AreEqual(1, animal.Legs);
        }

创建部分模拟对象

部分模拟对象可以用于测试抽象类中的模板方法。

例子

        [Test]
        public void CreatePartialMock_1()
        {
            MockRepository mocks = new MockRepository();
            AbstractProcessor processor = mocks.PartialMock<AbstractProcessor>();
            using (mocks.Record())
            {
                Expect.Call(processor.GetStatus()).Return(0);
                Expect.Call(processor.GetStatus()).Return(1);
            }
            Assert.AreEqual("OK", processor.Process());
            Assert.AreEqual("NOTOK", processor.Process());
            mocks.VerifyAll();
        }
    public abstract class AbstractProcessor
    {
        public string Process()
        {
            if (GetStatus() == 0)
            {
                return "OK";
            }
            else
            {
                return "NOTOK";
            }
        }
        public abstract int GetStatus();
    }

模拟对象属性调用


        [Test]
        public void Property_1()
        {
            MockRepository mocks = new MockRepository();
            Ticket ticket = mocks.StrictMock<Ticket>();
            using (mocks.Record())
            {
                Expect.Call(ticket.Movie).PropertyBehavior();
                Expect.Call(ticket.Price).PropertyBehavior();
            }
            ticket.Movie = "ABC";
            ticket.Price = 10.0f;
            Assert.AreEqual("ABC", ticket.Movie);
            Assert.AreEqual(10.0f, ticket.Price);
            ticket.VerifyAllExpectations();
        }
        [Test]
        public void Property_2()
        {
            MockRepository mocks = new MockRepository();
            Ticket ticket = mocks.StrictMock<Ticket>();
            using (mocks.Record())
            {
                Expect.Call(ticket.Movie).Return("ABC");
                Expect.Call(ticket.Price).Return(10.0f);
            }
            Assert.AreEqual("ABC", ticket.Movie);
            Assert.AreEqual(10.0f, ticket.Price);
            ticket.VerifyAllExpectations();
        }
        [Test]
        public void Property_3()
        {
            MockRepository mocks = new MockRepository();
            Book book = mocks.Stub<Book>();
            book.Name = "ABC";
            book.Price = 10.0f;
            Assert.AreEqual("ABC", book.Name);
            Assert.AreEqual(10.0f, book.Price);
        }

模拟delegate和设定模拟对象方法被调用的顺序

       [Test]
        public void Ordered_OK()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customer = mocks.StrictMock<ICustomerService>();
            using (mocks.Ordered())
            {
                customer.BuyTicket(null);
                customer.BuyBook(null);
            }
            customer.Replay();
            customer.BuyTicket(null);
            customer.BuyBook(null);
            customer.VerifyAllExpectations();
        }
        [Test]
        public void Ordered_ShouldFail()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customer = mocks.StrictMock<ICustomerService>();
            using (mocks.Ordered())
            {
                customer.BuyTicket(null);
                customer.BuyBook(null);
            }
            customer.Replay();
            customer.BuyBook(null);
            customer.BuyTicket(null);
            customer.VerifyAllExpectations();
        }
        [Test]
        public void Delegate_1()
        {
            MockRepository mocks = new MockRepository();
            var oo = mocks.DynamicMock<DoThing>();
            oo("BuyBook");
            oo.Replay();
            oo("BuyBook");
            oo.VerifyAllExpectations();
        }
        [Test]
        public void Delegate_Action()
        {
            MockRepository mocks = new MockRepository();
            var oo = mocks.DynamicMock<Action<string>>();
            oo("BuyBook");
            oo.Replay();
            oo("BuyBook");
            oo.VerifyAllExpectations();
        }
        [Test]
        public void Delegate_Func()
        {
            MockRepository mocks = new MockRepository();
            var oo = mocks.DynamicMock<Func<string,string>>();
            Expect.Call(oo("BuyBook")).Return("OK");
            oo.Replay();
            Assert.AreEqual("OK", oo("BuyBook"));
            oo.VerifyAllExpectations();
        }
        public delegate void DoThing(string thing);
    }

断言方法没有被调用

        [Test]
        public void When_user_forgot_password_should_save_user()
        {
            var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
            var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();
            User theUser = new User { HashedPassword = "this is not hashed password" };
            stubUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);
            stubUserRepository.Stub(x => x.Save(theUser));
            var controllerUnderTest = new LoginController(stubUserRepository, stubbedSmsSender);
            controllerUnderTest.ForgotMyPassword("ayende");
            stubUserRepository.AssertWasCalled(x => x.Save(theUser));
            stubbedSmsSender.AssertWasNotCalled(x => x.SendMessage(null));
        }

对模拟对象设置期望

[Test]
        public void Method_NoReturnValue()
        {
            MockRepository mocks = new MockRepository();
            ICustomerService customer = mocks.StrictMock<ICustomerService>();
            using (mocks.Record())
            {
                customer.BuyBook(null);
            }
        }
        
        [Test]
        public void Method_HasReturnValue()
        {
            MockRepository mocks = new MockRepository();
            var func = mocks.StrictMock<Func<string,string>>();
            using (mocks.Record())
            {
                Expect.Call(func("params")).Return("Result");
            }
        }
        [Test]
        public void Method_OutParameter()
        {
            MockRepository mocks = new MockRepository();
            var func = mocks.DynamicMock<DoThing1>();
            string strOut = "ABC";
            using (mocks.Record())
            {
                Expect.Call(func("", out strOut)).Return("Result").OutRef("xxx");
            }
            mocks.ReplayAll();
            Assert.AreEqual("Result", func("", out strOut));
            Assert.AreEqual("xxx", strOut);
            mocks.VerifyAll();
        }
        [Test]
        public void Method_RefParameter()
        {
            MockRepository mocks = new MockRepository();
            var func = mocks.DynamicMock<DoThing2>();
            string strRef = "ABC";
            using (mocks.Record())
            {
                Expect.Call(func("", ref strRef)).Return("Result").OutRef("xxx");
            }
            mocks.ReplayAll();
            Assert.AreEqual("Result", func("", ref strRef));
            Assert.AreEqual("xxx", strRef);
            mocks.VerifyAll();
        }
        [Test]
        public void Method_Options()
        {
            MockRepository mocks = new MockRepository();
            var func = mocks.DynamicMock<DoThing>();
            using (mocks.Record())
            {
                //返回值
                Expect.Call(func("")).Return("");
                //异常
                Expect.Call(func("")).Return("").Throw(new Exception());
                //方法允许使用的次数
                Expect.Call(func("")).Return("").Repeat.Any();
                Expect.Call(func("")).Return("").Repeat.Once();
                Expect.Call(func("")).Return("").Repeat.Twice();
                Expect.Call(func("")).Return("").Repeat.Times(3);
                //忽略方法参数
                Expect.Call(func("")).Return("").IgnoreArguments();
            }
        }
        public delegate string DoThing(string s1);
        public delegate string DoThing1(string s1, out string outs1);
        public delegate string DoThing2(string s1, ref string ref1);

设置期望时使用约束

       [Test]
        public void Constraints_Is_1()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            Expect.Call(customer.ShowTitle(""))
                  .Return("字符约束")
                  .Constraints(Rhino.Mocks.Constraints.Is.Matching<string>(x => x.StartsWith("cnblogs")));
            mocks.ReplayAll();
            Assert.AreEqual("字符约束", customer.ShowTitle("cnblogs my favoured"));
        }
        [Test]
        public void Constraints_Property_OK()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            using (mocks.Record())
            {
                customer.BuyBook(null);
                LastCall.On(customer).Constraints(Rhino.Mocks.Constraints.Property.Value("Name", "ABC"));
            }
            mocks.ReplayAll();
            customer.BuyBook(new Book { Name = "ABC" });
            mocks.VerifyAll();
        }
        [Test]
        public void Constraints_Property_ShouldFail()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            using (mocks.Record())
            {
                Expect.Call(delegate { customer.BuyBook(null); }).Constraints(Rhino.Mocks.Constraints.Property.Value("Name", "ABC"));
            }
            mocks.ReplayAll();
            customer.BuyBook(new Book { Name = "DDDABC" });
            mocks.VerifyAll();
        }
        [Test]
        public void Constraints_List_OK()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            Expect.Call(customer.SumPrice(null))
                  .Return(100)
                  .Constraints(Rhino.Mocks.Constraints.List.Equal(new int[]{100}));
            mocks.ReplayAll();
            Assert.AreEqual(100, customer.SumPrice(new int[]{100}));
        }
        [Test]
        public void Constraints_List_ShouldFail()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            Expect.Call(customer.SumPrice(null))
                  .Return(100)
                  .Constraints(Rhino.Mocks.Constraints.List.Equal(new int[] { 10 }));
            mocks.ReplayAll();
            Assert.AreEqual(100, customer.SumPrice(new int[] { 100 }));
        }
        [Test]
        public void Constraints_Text()
        {
            MockRepository mocks = new MockRepository();
            var customer = mocks.DynamicMock<ICustomerService>();
            Expect.Call(customer.ShowTitle(""))
                  .Return("字符约束")
                  .Constraints(Rhino.Mocks.Constraints.Text.StartsWith("cnblogs") && Rhino.Mocks.Constraints.Text.EndsWith("!"));
            mocks.ReplayAll();
            Assert.AreEqual("字符约束", customer.ShowTitle("cnblogs my favoured!"));
        }


设置期望时返回动态值(Do扩展方法的应用)

        [Test]
        public void SayHelloWorld()
        {
            MockRepository mocks = new MockRepository();
            INameSource nameSource = mocks.DynamicMock<INameSource>();
            Expect.Call(nameSource.CreateName(null, null))
                  .IgnoreArguments()
                  .Do(new NameSourceDelegate(Formal));
            mocks.ReplayAll();
            string expected = "Hi, my name is Ayende Rahien";
            string actual = new Speaker("Ayende", "Rahien", nameSource).Introduce();
            Assert.AreEqual(expected, actual);
        }
        delegate string NameSourceDelegate(string first, string surname);
        private string Formal(string first, string surname)
        {
            return first + " " + surname;
        }

创建模拟对象对象注意事项:

如果是类,必须包含无参数构造函数,被模拟的方法必须是虚方法;

无法模拟静态类和静态方法;

尽量通过被测试类的属性来设置被模拟对象(少用构造函数来建立依赖);

  • 如何运行测试用例

方式1(从VS中启动nunit.exe,可以对测试代码和产品代码进行调试):

在项目属性中的Debug面板中选中start external program并设置为{NUnitRoot}\bin\nunit.exe,然后启动测试工程。启动之后,打开测试工程对应的dll(一般是在*\bin\Debug\下)

运行你希望执行的测试用例

方式2

打开{NUnitRoot}\bin\nunit.exe,并打开测试工程对应的dll来运行你希望执行的测试用例

方式3(这个方式多用于持续集成环境中)

通过nunit-console.exe来运行,你必须在参数中指定你要运行dll,测试类,和输出结果的位置等相关参数

时间: 2024-12-27 23:20:20

单元测试 之 NUnit和RhinoMocks的相关文章

单元测试(一)-NUnit基础

单元测试作为提高代码和软件质量的有效途径,其重要性和益处自不必多说,虽然我没有实践过TDD之类,但坚信单元测试的积极作用.作为一种开发方法,单元测试早在上世纪70年代就已经在Smalltalk语言被运用了,这么多年来,单元测试一次又一次证明了自身的价值,在各种开发方式此起彼伏的浪潮中,经受住了时间的考验. 现在,俺也开始学习了,并在以后好好实践.这个系列的学习素材为Roy Osherove所著The Art of Unit Testing with examples in C#, 2nd Edi

单元测试工具NUnit的使用

  使用 NUnit 工具来进行单元测试 首先在要创建一个单元测试的项目,通常在原有的解决方案中添加新项目, 在弹出的项目类型中选择单元测试,项目的命名一般情况下与解决方案的名称相同后加UnitTest 然后在项目中添加一个单元测试的类, 类的名称与要测试的类的名字相同,也是后缀加UnitTest, 在单元测试项目中添加引用   NUnit.Framework.dll, 而后在单元测试的类的头部添加引用  using NUnit.Framework; 在测试类的上部添加特性  [TestFixt

VS2010整合NUnit进行单元测试

1.下载安装NUnit(最新win版本为NUnit-2.6.0.12051.msi) http://www.nunit.org/index.php?p=download 2.下载并安装VS的Visual Nunit 2010 插件  http://visualstudiogallery.msdn.microsoft.com/c8164c71-0836-4471-80ce-633383031099 注:可通过VS的“视图”->“其他窗口”找到并打开该插件(快捷键:Ctrl+F7) 3.新建测试项目

实现VS2010整合NUnit进行单元测试(转载)

代码编写,单元测试必不可少,简单谈谈Nunit进行单元测试的使用方式: 1.下载安装NUnit(最新win版本为NUnit-2.6.4.msi) http://www.nunit.org/index.php?p=download 2.下载并安装VS的Visual Nunit 2010 插件  http://visualstudiogallery.msdn.microsoft.com/c8164c71-0836-4471-80ce-633383031099 注:可通过VS的“视图”->“其他窗口”

MVC与单元测试实践之健身网站(一)-项目概述

前不久刚刚通过租房网站的开发学习了MVC,并随后学习了单元测试相关的基础,现在开始健身网站的开发,该项目将结合MVC与单元测试,在开发实践过程中,趁热打铁,巩固并运用之前的内容. 一 健身网站功能描述 关于健身网站的需求,主要从个人日常锻炼的需要出发,以达到辅助锻炼的目的.各应用商店中健身相关的APP也有不少,但始终无法找到一款很好满足增肌训练的.不花哨的.去社交化的.无跑步宗教的应用.于是刚好通过健身网站的开发,学习MVC和单元测试:如果顺利完成的话,也可作为日常锻炼之用. 网站的主要功能是:

【Unity游戏开发】浅谈Unity游戏开发中的单元测试

一.单元测试的定义与作用 单元测试定义:单元测试在传统软件开发中是非常重要的工具,它是指对软件中的最小可测试单元进行检查和验证,一般情况下就是对代码中的一个函数去进行验证,检查它的正确性.一个单元测试是一段自动化的代码,这段代码调用被测试的工作单元,之后对这个单元的单个最终结果的某些假设进行检验.单元测试使用单元测试框架编写,并要求单元测试可靠.可读并且可维护.只要产品代码不发生变化,单元测试的结果是稳定的.(百度的) 单元测试可以让你在软件开发的早期阶段发现 Bug,而不必到集成测试的时候才发

单元测试之道(使用NUnit)

首先来看下面几个场景你是否熟悉 1.你正在开发一个系统,你不断地编码-编译-调试-编码-编译-调试……终于,你负责的功能模块从上到下全部完成且编译通过!你长出一口气,怀着激动而 又忐忑的心情点击界面上的按钮,顿时你刚刚的轻松感烟消云散:系统无法正常工作,你想读的数据显示不出来,你想存的东西也送不到数据库……于是,你再次回 到IDE里,设断点.调试.一层一层跟踪,当你精疲力尽终于将数据送到数据库里,你又发现了其它问题,于是你继续设断点.调试.编译.调试…… 2.你狂躁地敲击着键盘和鼠标,咒骂着不断

.NetChajian

Code generation(代码自动生成) NVelocity CodeSmith X-Code .NET XGoF - NMatrix / DEVerest Compilation(编译工具) eXtensible C# - ResolveCorp Mono DotGNU - GNU Obfuscation(混淆加密) LSW-IL-Obfuscator - Lesser Software Demeanor for .NET - Wise Owl Salamander .NET Obfus

软件测试知识大全

一.软件测试基础篇 软件质量测试基础介绍 ● 软件质量与软件测试 ○ 仅依靠软件测试不能保证软件质量 ○ 进行全面质量管理 ● 软件开发与软件测试 ○ 具备UML或编程可以做更多层面的测试,如单元,白盒,性能测试 ● 测试工具与软件测试 ○ 按照用途分 · 测试管理工具 · 自动化功能测试工具 · 性能测试工具 · 单元测试工具 · 白盒测试工具 · 测试用例设计工具 ○ 按收费方式 · 商业测试工具 · 开源测试工具 · 免费测试工具 ○ 正确使用测试工具 ● MSF(Microsoft so