Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell QuickCheck中基于状态机的测试_Haskell_Erlang_Quickcheck - Fatal编程技术网

Haskell QuickCheck中基于状态机的测试

Haskell QuickCheck中基于状态机的测试,haskell,erlang,quickcheck,Haskell,Erlang,Quickcheck,Haskell QuickCheck是否具有John Hughes在以下谈话和论文中描述的基于状态机的功能- 如果不是,如何使用Haskell的QuickCheck进行有状态测试?例如,使用Haskell QuickCheck测试循环缓冲区而不在测试本身中重新实现核心逻辑的最佳方法是什么 我不认为QuickCheck中有任何明确的支持,但我认为Haskell中的一般方法类似于下面的示例 它根据一个模型(一个真实的Haskell列表)测试一个测试系统(自定义列表实例)。关键是生成任意的有状

Haskell QuickCheck是否具有John Hughes在以下谈话和论文中描述的基于状态机的功能-


如果不是,如何使用Haskell的QuickCheck进行有状态测试?例如,使用Haskell QuickCheck测试循环缓冲区而不在测试本身中重新实现核心逻辑的最佳方法是什么

我不认为QuickCheck中有任何明确的支持,但我认为Haskell中的一般方法类似于下面的示例

它根据一个模型(一个真实的Haskell列表)测试一个测试系统(自定义
列表
实例)。关键是生成任意的有状态基本操作序列(例如,
Push
Pop
、和
IsEmpty
),并以一元方式将其应用于测试系统和模型,在每次操作后检查post条件。在这种情况下,后置条件只是为了测试返回值(
pop
isEmpty
)的操作是否返回测试系统和模型的相同值,但可以轻松修改后置条件以测试其他后置条件(或添加前置条件)

如果测试失败,它将返回应用于空列表的最小操作序列,从而导致post条件失败

{-# LANGUAGE GADTs, StandaloneDeriving #-}

module ListTest where

import Test.QuickCheck
import Data.Monoid
import Control.Monad

-- |The system to test

data List a = Empty | Cons a (List a) deriving (Show, Eq)
push x lst = Cons x lst
pop (Cons x lst) = (Just x, lst)
pop Empty = (Nothing, Empty)
isEmpty Empty = True
isEmpty _     = False

-- |The model (based on plain Haskell lists)

type Model a = [a]
pushM = (:)
popM []     = (Nothing, [])
popM (x:xs) = (Just x, xs)
isEmptyM [] = True
isEmptyM _  = False

-- |Operations on lists of `a`s
data Op a = Push a | Pop | IsEmpty deriving (Show, Eq)
instance Arbitrary a => Arbitrary (Op a) where
  arbitrary = oneof ([Push <$> arbitrary, pure Pop, pure IsEmpty])

-- |For each op, return tuple of: (return values matched?, (new List, new Model))
compare_op :: (Eq a) => Op a -> (List a, Model a) -> (All, (List a, Model a))
compare_op (Push x) (lst, mdl) = -- True b/c no return value to compare
                                 (All True, (push x lst, pushM x mdl))
compare_op Pop      (lst, mdl) = let (y1, lst') = pop lst
                                     (y2, mdl') = popM mdl
                                 in  (All (y1 == y2), (lst', mdl'))
compare_op IsEmpty  (lst, mdl) = (All (isEmpty lst == isEmptyM mdl), (lst, mdl))

-- |The property that a sequence of operations has matching return values.
prop_model :: [Op Int] -> Bool
prop_model ops = (getAll . fst . foldM (flip compare_op) (Empty, [])) ops

main :: IO ()
main = quickCheck prop_model
{-#语言GADTs,独立派生}
模块列表测试在哪里
导入测试。快速检查
导入数据.幺半群
进口管制
--|要测试的系统
数据列表a=空| Cons a(列表a)派生(显示,等式)
推送x lst=Cons x lst
pop(Cons x lst)=(仅x,lst)
弹出空=(无,空)
isEmpty Empty=True
isEmpty=False
--|模型(基于普通Haskell列表)
类型模型a=[a]
pushM=(:)
popM[]=(无,[])
popM(x:xs)=(仅x,xs)
isEmptyM[]=True
isEmptyM=假
--| a名单上的业务
数据Op a=推送a | Pop | IsEmpty派生(Show,Eq)
实例任意a=>任意(Op a),其中
任意=其中一个([推任意,纯弹出,纯IsEmpty])
--|对于每个op,返回元组:(返回匹配的值?,(新列表,新模型))
比较操作::(等式a)=>操作a->(列表a,模型a)->(全部,(列表a,模型a))
比较_op(Push x)(lst,mdl)=--真实b/c无需比较的返回值
(全部为真,(推送x lst,推送M x mdl))
比较Pop(lst,mdl)=let(y1,lst')=Pop-lst
(y2,mdl')=popM mdl
in(全部(y1==y2),(lst',mdl'))
比较_opisempty(lst,mdl)=(All(IsEmpty lst==isEmptyM mdl),(lst,mdl))
--|操作序列具有匹配返回值的属性。
项目模型::[Op Int]->Bool
属性模型操作=(getAll.fst.foldM(翻转比较操作)(空,[])操作
main::IO()
main=快速检查道具模型

关于有状态或非状态函数的QuickCheck属性是相同的-它只是返回类型为
属性的另一个函数。你可能正在寻找一个真实的例子,使用Haskell QC检查真实的有状态系统,而不在测试中复制核心逻辑。QC中没有任何对前置/后置条件的支持吗?这段代码看起来与John Hughes幻灯片上的代码非常不同!另外,在不复制核心逻辑本身的情况下,业务应用程序的简化模型是否总是可能的?很多时候,现实世界应用程序中的逻辑被各种事物所掩盖。例如,可能有人采用了直接的逻辑,并将其分散在类层次结构或深度嵌套调用中,或者您可能正在处理microservices体系结构。可能并不总是能够建立一个简化的模型,但软件的复杂性会随着时间的推移而增加,所以很可能值得一试。