gpt4 book ai didi

c# - 为什么以及如何在遗留应用程序代码中实现初始单元测试

转载 作者:行者123 更新时间:2023-11-30 19:48:00 25 4
gpt4 key购买 nike

我正在将单元测试集成到现有的遗留应用程序中。在“Working with legacy application”一书和我读过的许多其他书籍中,写到在开始重构现有代码或集成新功能、纠正错误等过程之前,您始终应该编写单元测试......

在我阅读的大量示例中,重构方法的签名从不或很少中断,旧的单元测试在经过大量更改后仍然有效。原因是作者代码并没有遗留到我每天使用我认为的“遗留代码”时查看的代码。

在现实中,当您有一个遗留应用程序时,代码非常糟糕,您必须破坏方法的签名。如果你尝试用原来的方法编写单元测试,在仅仅 5 分钟的更改之后,你将破坏整个签名,而第一个测试将被扔进垃圾桶。

举个例子,看下面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyCompany.Accouting
{
public class DataCreator
{
public static System.Data.DataSet CreateInvoice(
System.Data.DataSet customer,
System.Data.DataSet order,
string mails,
ref bool isValid)
{
System.Data.DataSet invoice = new System.Data.DataSet();

int taxGroupId =
ApplicationException.ShareConnection.ExecuteScalar(
"SELECT Id FROM TaxGroup WHERE TaxGroup.IsDefault");

Application.ShareConnection.ExecuteNonQuery(
"INSERT INTO Invoice (CustomerId, EffectiveDate) VALUES(?,?)",
customer.Tables[0].Rows[0]["Id"], System.DateTime.Now);

int invoiceId;

invoiceId = Application.SharedConnection.ExecuteScalar("SELECT @@IDENTITY");

Application.SharedConnection.ExecuteNonQuery(
"INSERT INTO InvoiceLine (ProductId, Quantity, InvoiceId) VALUES(?,?,?)", ,
order.Tables[0].Rows[0]["ProductId"], order.Tables[0].Rows[0]["Quantity"], invoiceId);

foreach(string mail in mails.Split(';'))
{
Application.MailSender.Send(mail);
}

isValid = true;

System.Data.DataRow row = invoice.Tables[0].NewRow();
row["Id"] = invoiceId;

invoice.Tables[0].Rows.Add(row);

return invoice;
}
}
}

如您所见,这里有很多错误代码。

重构后,方法将不再是静态的,ref 参数将被移除,DataSet 将转换为 POCOs 对象,对“Application”等全局对象的访问将被动态注入(inject)的属性所取代,以及许多其他变化就像实现接口(interface)一样,检查类名、命名空间和许多其他东西。事实上,这段代码完全是垃圾,应该扔掉并从头开始重写。

如果我为原始静态方法创建单元测试,当删除 static 关键字以便以更面向对象的方式使用该类时,测试将立即中断。将 DataSet 更改为 Poco 等也是如此......

为什么要创建一个单元测试,如果在 5 分钟内,我会丢弃这个测试?这个测试有什么帮助?

在这种情况下您将使用哪种策略?

非常感谢。

最佳答案

这里的关键是选择您实际要进行单元测试的点。在您的情况下,对要替换的确切方法进行测试没有意义。相反,需要为应用程序中调用您的方法的每个点创建一个测试,以确保特定功能仍然正常工作。

原因是,一旦您完成了 DataCreator 类的重构,您将不得不返回调用它的所有区域并进行更改。在进行更改之前对这些区域进行测试将确保您的功能相同。

见下文:

public class SomeClass {
public Boolean DoSomething() {
OtherClass oc = new OtherClass();
return oc.DoSomethingElse("param1", "param2") == "true";
}
}


public class OtherClass {
public String DoSomethingElse(String param1, String param2) {
// horrible code here which never uses the second parameter

return "true";
}
}

在上面的示例中,您可能非常希望重构 DoSomethingElse 以将返回类型更改为 bool 值并消除第二个参数。

因此,您首先对 SomeClass.DoSomething 方法进行单元测试。然后将 OtherClass 重构为您满意的内容,确保 DoSomething 的最终结果相同。

当然,在这种情况下,您要确保对每个调用“DoSomethingElse”的事物进行单元测试

关于c# - 为什么以及如何在遗留应用程序代码中实现初始单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5905557/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com