我对单元测试有些新意。关于正确测试的一件事(现在)让我感到困惑。
例如,如果主方法没有状态且只有控制台输出,那么如何测试它?像这样,myServer方法&国家是私人的?
public static void main(String[] args)
{
Server myServer = new Server()
if(myServer.start())
System.out.println("started");
else
System.out.println("failed");
}
我不想更改我的代码并公开我的服务器方法&声明他们是公开的。
注意,我不是在问如何测试myServer.start(),我问的是如何测试main()本身。
请告诉我。
谢谢你们, JBU
答案 0 :(得分:8)
主要方法应该非常薄,只是让球滚动。因此通常没有经过测试 例如a .net Winforms app主要方法可能包含
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
如果你的主要方法做了很多事情,可以考虑提取一个方法(如果需要的话,提到一个新的方法)。例如如下所示...(没有JavaIDE方便.. foll .net代码应该很容易翻译)
static void Main()
{
new MainApp().Run();
}
现在如果Run可以测试..主要也被覆盖。让我们看看MainApp。将启动服务器和记录结果的2个任务重构为2个方法。
public class MainApp
{
private Server m_Server;
public MainApp():this(new Server())
{}
public MainApp(Server s)
{ m_Server = s; }
public void Run()
{ Log(LaunchServer()); }
private string LaunchServer()
{ return (m_Server.start() ? "started" : "failed"); }
protected virtual void Log(string sMessage)
{ System.Console.WriteLine(sMessage); }
}
现在让我们看看测试代码......我将使用“子类和覆盖”技巧来缓存结果,如下所示。 (你也可以根据口味使用Mocks)
public class FakeApp : MainApp
{
private string sLastLoggedMessage;
public FakeApp(Server s) : base(s) { }
public string getLastLoggedMessage()
{ return sLastLoggedMessage; }
protected override void Log(string sMessage)
{ sLastLoggedMessage = sMessage; }
}
测试现在是微不足道的
[TestFixture]
public class TestMainApp
{
[Test]
public void TestRun()
{
Server s = new Server();
FakeApp f = new FakeApp(s);
f.Run();
Assert.AreEqual("started", f.getLastLoggedMessage());
}
}
如果您无法根据需要强制Server.start()成功或失败。您可以创建一个FakeServer ..子类并覆盖start()以返回固定值。
如果方法有效,可以对其进行测试。如果没有,它应该不复存在。重构它。 HTH
答案 1 :(得分:4)
您(通常)不会对main()方法进行单元测试。在您的情况下,您可以对Server类(可能还有其他类)进行单元测试,即测试它的公共接口。
答案 2 :(得分:1)
由于您的方法只有一个方向的信息流 - 对协作者对象(在此示例中为:Server对象),并且不以其他方式返回值或抛出异常,您可以提供模拟协作者对象(模拟服务器)在你的例子中),它将配置对从main()方法接收的方法调用及其参数的期望。
您可以使用其中一个模拟对象框架,例如: EasyMock的。
在单元测试期间,当main()方法对其进行的调用与配置的期望不匹配时,模拟对象将抛出一个正确的异常。
当然,为了提供一个模拟对象,你必须在对象实例化方面稍微修改一下方法 - 使“Server”成为一个接口,而不是一个具体的类,并使用一个框架(如Spring)而不是手动实例化您的Server对象,例如而不是:
Server myServer = new Server();
你有这个:
Server myServer = applicationContext.getBean("server");
您将为生产应用程序和单元测试创建单独的Spring应用程序上下文配置,不同之处在于将使用XML文件配置生产的应用程序上下文,而对于单元测试将以编程方式创建并使用mock填充测试类的setUp()方法中的对象。
答案 3 :(得分:0)
如果您希望将此案例以及其他许多案件清除,我可以建议Pragmatic Unit Testing系列吗?
答案 4 :(得分:0)
一般来说,main()不是“单位”,并且难以设计单元测试。按照惯例,main()应该返回一个int来表示错误状态。也许这就是你所需要的一切?
答案 5 :(得分:0)
将代码包装在非主方法中并测试; - )
严肃地说,其他人都说了什么
但是如果你必须...进行单元测试运行DOS shell中的控制台应用程序(请参阅Process对象),并将STDOUT重定向到文件,然后读取输出文件的内容以查看它是否显示为“started” “或”失败“,无论你期望什么