我知道可以使用反射或其他解决方法使用PHPUnit测试私有/受保护的方法.
但是大多数消息来源告诉我,在类中编写私有方法的测试并不是最好的做法.
您应该将类测试为"黑盒子" - 您只需通过将输入与输出进行比较而不考虑内部机制来测试预期行为.编写类的测试还应通过显示缺少代码覆盖率来通知您未使用的私有方法.
当我测试我的类并生成HTML报告时,它会显示测试未涵盖的私有方法,即使它们被调用的行是绝对执行/覆盖的.我知道私有方法被执行,因为如果它们不是我班上的断言就不会通过.
这是PHPUnit中的预期行为吗?我是否可以争取100%的覆盖率,同时仅间接测试私有方法?
一些简化的示例代码(在Symfony2中使用RestBundle):
class ApiController extends FOSRestController {
/*
* @REST\View()
* @REST\Get("/api/{codes}")
*/
public function getCodesAction($codes) {
$view = new View();
$view->setHeader('Access-Control-Allow-Origin', '*');
$view->setData(array('type' => 'codes','data' => $this->_stringToArray($codes)));
$view->setFormat('json')->setHeader('Content-Type', 'application/json');
return $this->handleView($view);
}
private function _stringToArray($string){
return explode('+',$string);
}
Run Code Online (Sandbox Code Playgroud)
公共函数显示为"覆盖",私有函数是间接覆盖的,但在PHPUnit报告中显示为红色.
测试:
class ApiControllerTest extends WebTestCase {
public function test_getCodesAction(){
$client = static::createClient();
$client->request('GET', '/api/1+2+3');
$this->assertContains('{"type": "codes", "data": [1,2,3]}', $client->getResponse()->getContent());
}
}
Run Code Online (Sandbox Code Playgroud)
这当然是一个愚蠢的例子,我也可以在公共函数中包含explode(); 但我正在编写的控制器包含更多复杂且可重复使用的私有函数,这些函数以更复杂的方式转换数据(但仍然没有副作用).
我正在 PHP 中读取流,使用 proc_open 和 fgets($stdout),试图获取每一行。
许多 linux 程序(包管理器、wget、rsync)只使用 CR(回车)字符来表示定期“就地”更新的行,例如下载进度。我想在它们发生时立即捕获这些更新(作为单独的行)。
目前,fgets($stdout) 只会一直读取直到 LF,所以当进度非常缓慢时(例如大文件),它只会继续读取直到完全完成,然后将所有更新的行作为一个长字符串返回,包括CR。
我尝试设置“mac”选项以将 CR 检测为行尾:
ini_set('auto_detect_line_endings',true);
Run Code Online (Sandbox Code Playgroud)
但这似乎不起作用。
现在,stream_get_line 将允许我将 CR 设置为换行符,但不是将 CRLF、CR 和 LF 都视为分隔符的“一网打尽”解决方案。
我当然可以阅读整行,使用各种 PHP 方法拆分它并用 LF 替换所有类型的换行符,但它是一个流,我希望 PHP 能够在它仍在运行时获得进度指示。
所以我的问题:
如何从 STDOUT 管道(从 proc_open)读取数据,直到发生 LF或CR,而不必等到整行都输入?
提前致谢!
我使用 Fleshgrinder 的过滤器类将流中的 \r 替换为 \n(参见已接受的答案),并将 fgets() 替换为 fgetc() 以获得对 STDOUT 内容的更多“实时”访问:
$stdout = $proc->pipe(1);
stream_filter_register("EOL", "EOLStreamFilter");
stream_filter_append($stdout, "EOL");
while (($o = fgetc($stdout))!== false){
$out .= $o; // buffer the characters into line, until \n. …Run Code Online (Sandbox Code Playgroud) 我只是在探索Haskell的乐趣,并了解语言.我认为以下行为很有趣,我找不到发生这种情况的原因.
这是一个经常被引用的Haskell代码,它一直计算pi直到被中断,稍微修改以给出一个连续的字符列表而不是一个整数列表:
main :: IO ()
main = do putStrLn pi'
pi' :: [Char]
pi' = concat . map show $ g(1,0,1,1,3,3) where
g(q,r,t,k,n,l) =
if 4*q+r-t<n*t
then n : g(10*q,10*(r-n*t),t,k,div(10*(3*q+r))t-10*n,l)
else g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
Run Code Online (Sandbox Code Playgroud)
如果我从prelude运行它,它会开始连接类似pi数字的字符串:
?> putStrLn pi'
31415926535897932384626433832795028841971 ...等等
按预期工作,它立即开始喷出数字.
现在这是我刚刚写的一段具有相同结构的代码.从数学的角度来看,它完全没用,我只是在弄乱Haskell如何工作.操作要简单得多,但它确实具有相同的类型,子函数也是如此(除了较小的元组).
main :: IO ()
main = do putStrLn func
func :: [Char]
func = concat . map show $ h(1,2,1) where
h(a,b,c) =
if a <= 1000
then a : h((div a 1)+2*b,b,1)
else h(b,div (b-3) (-1),div a a) …Run Code Online (Sandbox Code Playgroud) 我正在处理一个相当复杂的查询构建器(在存储库函数中),它使用很多东西partial c.{id,name,created}和一堆fetchjoins来尝试保持数据量和查询量.
但这还不够,但无论如何前端表示都是分页的,所以我想在需要时进行一些ajax调用来获取数据.
$qb = $this->createQueryBuilder('c')
->select('a whole bunch')
->join('many joins')
->setFirstResult(0)
->setMaxResults(10)
Run Code Online (Sandbox Code Playgroud)
上面的方法不适用于复杂的连接,我做了setMaxResults(10)2个结果,setMaxResults(1000)得到118个结果.Doctrine建议使用他们的Pagination类,因为它将正确处理计数/迭代.
现在,如果我遍历由提供的Iterator对象new Paginator($query, true),那么一切正常,但调用存储库函数的代码期望从中获取一个数组getArrayResult.
迭代器包含完整的实体对象,这意味着我必须重写所有服务以使用方法而不是数组键.
有没有办法将Paginator与ArrayResult一起使用?
作为一个例子,我有一个带前后轮的自行车,它们都只有一个Int来代表直径.
type Wheel = Int
data Bike = Bike { frontwheel :: Wheel, rearwheel :: Wheel }
deriving (Show)
mybike = Bike 24 26
Run Code Online (Sandbox Code Playgroud)
现在我想更换一个轮子,因为我不喜欢它们的尺寸不同:
replaceFrontWheel :: Bike -> Wheel -> Bike
replaceFrontWheel bike wheel = bike { frontwheel = wheel }
repairedbike = replaceFrontWheel mybike 26
Run Code Online (Sandbox Code Playgroud)
这样可行!
但是,如果我想要一个可以替换前轮或后轮的功能呢?毕竟两个轮子都是Wheel(Int)类型,所以为什么不使用单个函数来实现它,该函数也将该字段作为参数:
replaceWheel bike position wheel = bike { position = wheel }
repairedbike = replaceWheel mybike frontwheel 26
Run Code Online (Sandbox Code Playgroud)
我明白为什么这不起作用.position不被解释为具有值frontwheel,但作为(不存在)字段position的Bike.
是否有(JS)mybike[position] = …
我需要这样的清单:
[(16,2), (14,3), (15,3), (16,3), (18,3), (19,3), (12,4), (13,4), (14,4)]
Run Code Online (Sandbox Code Playgroud)
但是,要长得多。此列表中确实有一些非常大的范围模式,但也有不规则之处。因此,写下所有元组是不可行的,但是我也无法创建简单的listcomp。
我想使用:
[(16,2), (x,3) for x in range(14,19), (x,4) for x in range(12,14)]
Run Code Online (Sandbox Code Playgroud)
但是根据文档,这[x, y for ...]是不允许的,并且我的示例被解释为由2个带括号的元组组成的无括号元组,而不是后跟列表理解的元组。
有什么办法吗?