主持人注意: 这里已经发布了39个答案(其中一些已被删除). 在您发布答案之前,请考虑您是否可以在讨论中添加有意义的内容.你很可能只是重复别人已经说过的话.
我偶尔发现自己需要在公共类中创建一个私有方法,只是为它编写一些单元测试.
通常这是因为该方法包含在类中的其他方法之间共享的逻辑,并且它自己测试逻辑更加整洁,或者另一个原因可能是我想测试同步线程中使用的逻辑而不必担心线程问题.
其他人发现自己这样做,因为我真的不喜欢这样做吗?我个人认为奖金超过了公开方法的问题,并没有真正提供课外的任何服务......
UPDATE
感谢大家的回答,似乎激起了人们的兴趣.我认为普遍的共识是测试应该通过公共API进行,因为这是一个类将被使用的唯一方式,我同意这一点.我上面提到过的几个我上面提到的案例都是不常见的案例,我认为这样做的好处是值得的.
但是,我可以看到每个人都指出它永远不应该发生.当我考虑更多时,我认为更改代码以适应测试是一个坏主意 - 毕竟我认为测试是一种支持工具,并且如果你愿意,将系统更改为"支持支持工具",则是公然的糟糕的做法.
我发现讨论你是否测试私人方法的信息.
我已经决定,在某些类中,我想要保护方法,但测试它们.其中一些方法是静态的和简短的.由于大多数公共方法都使用它们,我可能会在以后安全地删除测试.但是对于从TDD方法开始并避免调试,我真的想测试它们.
我想到了以下几点:
哪个是最佳做法?还有别的事吗?
看来,JUnit会自动将受保护的方法更改为公开,但我没有深入了解它.PHP不允许通过反射.
在TDD开发中,您通常首先要创建接口,然后开始针对该接口编写单元测试.当您逐步完成TDD过程时,您最终会创建一个实现接口的类,然后在某些时候您的单元测试将通过.
现在我的问题是关于我可能必须在我的类中编写的私有和受保护的方法,以支持接口公开的方法/属性:
班级中的私有方法是否应该有自己的单元测试?
班级中受保护的方法是否应该有自己的单元测试?
我的想法:
特别是因为我正在编写接口,我不应该担心受保护/私有方法,因为它们是黑盒子.
因为我正在使用接口,所以我正在编写单元测试以验证定义的合同是否由实现接口的不同类正确实现,所以我再也不担心私有/受保护的方法,并且应该通过调用它的单元测试来执行它们.接口定义的方法/属性.
如果我的代码覆盖率没有显示受保护/私有方法被命中,那么我没有正确的单元测试,或者我有没有被使用的代码,应该被删除.
在阅读" 你的/你的圈复杂度有什么限制? "之后,我意识到我的很多同事对我们项目的新QA政策非常恼火:每个功能不再有10个圈复杂度.
含义:不超过10'if','else','try','catch'和其他代码工作流程分支语句.对.正如我在' 你测试私人方法吗?',这样的政策有很多好的副作用.
但是:在我们(200人 - 7年)项目开始时,我们很高兴地记录(不,我们不能轻易地将其委托给某种' 面向方面编程 '的日志方法).
myLogger.info("A String");
myLogger.fine("A more complicated String");
...
Run Code Online (Sandbox Code Playgroud)
当我们的系统的第一个版本上线时,我们遇到了巨大的内存问题,不是因为日志记录(在某一点被关闭),而是因为日志参数(字符串),总是被计算,然后传递给'info()'或'fine()'函数,只是发现日志记录级别为"OFF",并且没有记录日志!
所以QA回来并敦促我们的程序员进行条件记录.总是.
if(myLogger.isLoggable(Level.INFO) { myLogger.info("A String");
if(myLogger.isLoggable(Level.FINE) { myLogger.fine("A more complicated String");
...
Run Code Online (Sandbox Code Playgroud)
但是现在,由于每个功能限制的"无法移动"10个圈复杂度级别,他们认为他们在其功能中放入的各种日志被视为负担,因为每个"if(isLoggable())"是计为+1圈复杂度!
因此,如果一个函数有8'if','else'等等,在一个紧密耦合的不易共享的算法中,以及3个关键的日志操作......它们违反了限制,即使条件日志可能不是真的该功能的复杂性的一部分......
你会如何解决这种情况?
我在项目中看到过几个有趣的编码演变(由于这个'冲突'),但我只是想先了解你的想法.
谢谢你的所有答案.
我必须坚持认为问题不是"格式化"相关,而是"参数评估"相关(评估可能非常昂贵,只是在调用一个什么都不做的方法之前)
所以当写一个上面的"A String"时,我实际上意味着机能缺失(),与机能缺失()返回一个字符串,并且是一个复杂的方法收集的调用和计算所有类型的日志数据被记录器...与否(因此该问题,并显示义务,以使用条件记录,因此人为增加'圈复杂度'的实际问题......)
我现在得到你们中某些人提出的" 可变函数"点(谢谢John).
注意:java6中的快速测试表明我的varargs函数在被调用之前会对其参数进行求值,所以它不能用于函数调用,而是用于'Log Retriever object'(或'function wrapper'),其中toString( )只有在需要时才会被调用.得到它了.
我现在已经发表了关于这个主题的经验.
我会留在那里直到下周二投票,然后我会选择你的一个答案.
再次,谢谢你的所有建议:)
language-agnostic logging coding-style cyclomatic-complexity
我有一个私有方法的伴侣对象,如下所示:
package com.example.people
class Person(val age: Int)
object Person {
private def transform(p: Person): Person = new Person(p.age + 1)
}
Run Code Online (Sandbox Code Playgroud)
我想测试这个方法,例如:
class PersonSpec extends FlatSpec {
"A Person" should "transform correctly" in {
val p1 = new Person(1)
val p2 = Person.transform(p1) // doesn't compile, because transform is private!
assert( p2 === new Person(2) )
}
}
Run Code Online (Sandbox Code Playgroud)
有关测试代码访问私有方法的任何帮助吗?
实际上,正如它所写,我可能能够创建一个子类Person,但如果Person被声明为final或sealed?
谢谢!
我想使用GoogleTest测试一些私有方法.
class Foo
{
private:
int bar(...)
}
Run Code Online (Sandbox Code Playgroud)
GoogleTest允许使用两种方法.
选项1
使用FRIEND_TEST:
class Foo
{
private:
FRIEND_TEST(Foo, barReturnsZero);
int bar(...);
}
TEST(Foo, barReturnsZero)
{
Foo foo;
EXPECT_EQ(foo.bar(...), 0);
}
Run Code Online (Sandbox Code Playgroud)
这意味着在生产源文件中包含"gtest/gtest.h".
方案2
将测试夹具声明为类的朋友并在夹具中定义访问器:
class Foo
{
friend class FooTest;
private:
int bar(...);
}
class FooTest : public ::testing::Test
{
protected:
int bar(...) { foo.bar(...); }
private:
Foo foo;
}
TEST_F(FooTest, barReturnsZero)
{
EXPECT_EQ(bar(...), 0);
}
Run Code Online (Sandbox Code Playgroud)
方案3
该PIMPL方法.
有关详细信息:Google测试:高级指南.
有没有其他方法来测试私有方法?每种选择有哪些优缺点?
我正在为nodejs应用程序编写一些测试.假设我有一个这样的模块:
module.exports = function myModule(moduleParam) {
var someVar;
....
....
function helper(param) {
return param + someVar;
}
return {
doSomething: function (bar) {
....
....
var foo = helper(bar);
....
....
}
};
};
Run Code Online (Sandbox Code Playgroud)
假设'helper'函数仅在模块中有用,不应暴露给外部.
测试它的"最佳实践"是什么?(当然,我可以测试doSomething函数作为一个整体,但是这样,'helper'函数在特定情况下以'黑盒'的方式进行测试).
我正在使用nodeunit作为测试框架,但是我可以根据需要进行更改.
TDD的一个方面我从未完全理解.
假设有人要求您实现一个简单的Stack对象.如果您已经正确完成了设计,那么您将获得一个非常简洁的API.假设:push(),pop()和isEmpty().除此之外的任何事情都会过度消耗需求,并让用户有太多空间来捣乱您的代码.
所以现在让我们假设您要对代码进行单元测试.如果您所有的公共方法都只是上面显示的三个方法,那么您如何做到这一点?到目前为止,这些方法只会进行测试.
因此,要么添加私有方法,它们根本不会帮助您,因为它们对您的单元测试用例不可见.或者你将这些方法公之于众,那就是你努力工作的简约API.现在用户将要乱用你的堆栈,肯定会出现错误.
您如何处理打开公共测试方法与干净简单API的这种困境?
编辑:只是为了指向正确的方向,获得技术指针(例如"使用此hack来暴露私有方法"等等)会很高兴但是我对更通用的答案更感兴趣这两个概念更重要,以及您如何处理这个主题.
我开始编写一些javascript测试并试图找出检查模块构造函数的私有成员的最佳方法.例如,在下面的示例中,我使用揭示模块模式将公共API暴露给我的模块.我想测试privateVar在$.getJSONajax请求的回调期间正确设置.
第二个测试it('should update privateVar', ...),不起作用,因为myModule.privateVar(故意)不在模块的公共API中.
所以,我的问题是,测试这种行为的最佳方法是什么,而不必将privateVar作为公共API的一部分?是否有更好的方法可以将此代码用于测试,或者使用像SinonJs这样的方法来监视私有成员?
define('myModule',
['jquery'],
function ($) {
var
myVar = "something",
privateVar = "something else",
doSomething = function() {
return $.getJSON('http://myapi.com/do-something', { requestData : "some data" }, function(response){
myVar = response.data.value1;
privateVar = response.data.value2;
});
};
return {
doSomething : doSomething,
myVar : myVar
};
}
);
define('test/test.myModule',
['myModule', 'chai', 'sinon', 'mocha'],
function (myModule, chai, sinon) {
describe("myModule", function() {
var expect = chai.expect; …Run Code Online (Sandbox Code Playgroud) unit-testing ×7
tdd ×3
testing ×3
java ×2
javascript ×2
c# ×1
c++ ×1
coding-style ×1
commonjs ×1
googletest ×1
logging ×1
mocha.js ×1
node.js ×1
php ×1
phpunit ×1
private ×1
scala ×1
scalatest ×1
sinon ×1