go命令教程: http://wiki.jikexueyuan.com/project/go-command-tutorial/0.5.html
Go测试
第一个测试 “Hello Test!”
首先,在我们$GOPATH/src目录下创建hello目录,作为本文涉及到的所有示例代码的根目录。
然后,新建名为hello.go的文件,定义一个函数hello()
,功能是返回一个由若干单词拼接成句子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package hello func hello() string { words := []string{ "hello" , "func" , "in" , "package" , "hello" }
wl := len(words)
sentence := ""
for key, word := range words {
sentence += word
if key < wl-1 {
sentence += " "
} else {
sentence += "."
}
}
return sentence
} |
接着,新建名为hello_test.go的文件,填入如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package hello import ( "fmt"
"testing"
) func TestHello(t *testing.T) { got := hello()
expect := "hello func in package hello."
if got != expect {
t.Errorf( "got [%s] expected [%s]" , got, expect)
}
} func BenchmarkHello(b *testing.B) { for i := 0; i < b.N; i++ {
hello()
}
} func ExampleHello() { hl := hello()
fmt.Println(hl)
// Output: hello func in package hello.
} |
最后,打开终端,进入hello目录,输入go test
命令并回车,可以看到如下输出:
1
2
|
PASS ok hello 0.007s |
编写测试代码
Golang的测试代码位于某个包的源代码中名称以_test.go结尾的源文件里,测试代码包含测试函数、测试辅助代码和示例函数;测试函数有以Test开头的功能测试函数和以Benchmark开头的性能测试函数两种,测试辅助代码是为测试函数服务的公共函数、初始化函数、测试数据等,示例函数则是以Example开头的说明被测试函数用法的函数。
大部分情况下,测试代码是作为某个包的一部分,意味着它可以访问包中不可导出的元素。但在有需要的时候(如避免循环依赖)也可以修改测试文件的包名,如package hello的测试文件,包名可以设为package hello_test。
功能测试函数
功能测试函数需要接收*testing.T类型的单一参数t,testing.T 类型用来管理测试状态和支持格式化的测试日志。测试日志在测试执行过程中积累起来,完成后输出到标准错误输出。
下面是从Go标准库摘抄的 testing.T类型的常用方法的用法:
测试函数中的某条测试用例执行结果与预期不符时,调用t.Error()
或t.Errorf()
方法记录日志并标记测试失败
1
2
3
4
5
6
7
8
9
10
|
# /usr/local/go/src/bytes/compare_test.go func TestCompareIdenticalSlice(t *testing.T) { var b = []byte( "Hello Gophers!" )
if Compare(b, b) != 0 {
t.Error( "b != b" )
}
if Compare(b, b[:1]) != 1 {
t.Error( "b > b[:1] failed" )
}
} |
使用t.Fatal()
和t.Fatalf()
方法,在某条测试用例失败后就跳出该测试函数
1
2
3
4
5
6
7
8
9
10
|
# /usr/local/go/src/bytes/reader_test.go func TestReadAfterBigSeek(t *testing.T) { r := NewReader([]byte( "0123456789" ))
if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
t.Fatal(err)
}
if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
t.Errorf( "Read = %d, %v; want 0, EOF" , n, err)
}
} |
使用t.Skip()
和t.Skipf()
方法,跳过某条测试用例的执行
1
2
3
4
5
6
7
8
9
|
# /usr/local/go/src/archive/zip/zip_test.go func TestZip64(t *testing.T) { if testing.Short() {
t.Skip( "slow test; skipping" )
}
const size = 1 << 32 // before the "END\n" part
buf := testZip64(t, size)
testZip64DirectoryRecordLength(buf, t)
} |
执行测试用例的过程中通过t.Log()
和t.Logf()
记录日志
1
2
3
4
5
6
7
8
9
10
11
|
# /usr/local/go/src/regexp/exec_test.go func TestFowler(t *testing.T) { files, err := filepath.Glob( "testdata/*.dat" )
if err != nil {
t.Fatal(err)
}
for _, file := range files {
t.Log(file)
testFowler(t, file)
}
} |
使用t.Parallel()
标记需要并发执行的测试函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# /usr/local/go/src/runtime/stack_test.go func TestStackGrowth(t *testing.T) { t.Parallel()
var wg sync.WaitGroup
// in a normal goroutine
wg.Add(1)
go func() {
defer wg.Done()
growStack()
}()
wg.Wait()
// ...
} |
性能测试函数
性能测试函数需要接收*testing.B类型的单一参数b,性能测试函数中需要循环b.N次调用被测函数。testing.B 类型用来管理测试时间和迭代运行次数,也支持和testing.T相同的方式管理测试状态和格式化的测试日志,不一样的是testing.B的日志总是会输出。
下面是从Go标准库摘抄的 testing.B类型的常用方法的用法:
在函数中调用t.ReportAllocs()
,启用内存使用分析
1
2
3
4
5
6
7
8
9
10
|
# /usr/local/go/src/bufio/bufio_test.go func BenchmarkWriterFlush(b *testing.B) { b.ReportAllocs()
bw := NewWriter(ioutil.Discard)
str := strings.Repeat( "x" , 50)
for i := 0; i < b.N; i++ {
bw.WriteString(str)
bw.Flush()
}
} |
通过 b.StopTimer()
、b.ResetTimer()
、b.StartTimer()
来停止、重置、启动 时间经过和内存分配计数
1
2
3
4
5
6
7
8
9
10
11
12
|
# /usr/local/go/src/fmt/scan_test.go func BenchmarkScanInts(b *testing.B) { b.ResetTimer()
ints := makeInts(intCount)
var r RecursiveInt
for i := b.N - 1; i >= 0; i-- {
buf := bytes.NewBuffer(ints)
b.StartTimer()
scanInts(&r, buf)
b.StopTimer()
}
} |
调用b.SetBytes()
记录在一个操作中处理的字节数
1
2
3
4
5
6
7
|
# /usr/local/go/src/testing/benchmark.go func BenchmarkFields(b *testing.B) { b.SetBytes(int64(len(fieldsInput)))
for i := 0; i < b.N; i++ {
Fields(fieldsInput)
}
} |
通过b.RunParallel()
方法和 *testing.PB类型的Next()
方法来并发执行被测对象
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# /usr/local/go/src/sync/atomic/value_test.go func BenchmarkValueRead(b *testing.B) { var v Value
v.Store( new ( int ))
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
x := v.Load().(* int )
if *x != 0 {
b.Fatalf( "wrong value: got %v, want 0" , *x)
}
}
})
} |
测试辅助代码
测试辅助代码是编写测试代码过程中因代码重用和代码质量考虑而产生的。主要包括如下方面:
引入依赖的外部包,如每个测试文件都需要的 testing 包等:
1
2
3
4
5
6
7
8
9
10
|
# /usr/local/go/src/log/log_test.go: import ( "bytes"
"fmt"
"os"
"regexp"
"strings"
"testing"
"time"
) |
定义多次用到的常量和变量,测试用例数据等:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
# /usr/local/go/src/log/log_test.go: const (
Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
Rline = `(57|59):` // must update if the calls to l.Printf / l.Print below move
Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline
) // ... var tests = []tester{ // individual pieces:
{0, "" , "" },
{0, "XXX" , "XXX" },
{Ldate, "" , Rdate + " " },
{Ltime, "" , Rtime + " " },
{Ltime | Lmicroseconds, "" , Rtime + Rmicroseconds + " " },
{Lmicroseconds, "" , Rtime + Rmicroseconds + " " }, // microsec implies time
{Llongfile, "" , Rlongfile + " " },
{Lshortfile, "" , Rshortfile + " " },
{Llongfile | Lshortfile, "" , Rshortfile + " " }, // shortfile overrides longfile
// everything at once:
{Ldate | Ltime | Lmicroseconds | Llongfile, "XXX" , "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " " },
{Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX" , "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " " },
} |
和普通的Golang源代码一样,测试代码中也能定义init函数,init函数会在引入外部包、定义常量、声明变量之后被自动调用,可以在init函数里编写测试相关的初始化代码。
1
2
3
4
5
6
7
8
|
# /usr/local/go/src/bytes/buffer_test.go func init() { testBytes = make([]byte, N)
for i := 0; i < N; i++ {
testBytes[i] = 'a' + byte(i%26)
}
data = string(testBytes)
} |
封装测试专用的公共函数,抽象测试专用的结构体等:
1
2
3
4
5
6
7
8
9
10
11
12
|
# /usr/local/go/src/log/log_test.go: type tester struct {
flag int
prefix string
pattern string // regexp that log output must match; we add ^ and expected_text$ always
} // ... func testPrint(t *testing.T, flag int , prefix string, pattern string, useFormat bool ) {
// ...
} |
示例函数
示例函数无需接收参数,但需要使用注释的 Output: 标记说明示例函数的输出值,未指定Output:标记或输出值为空的示例函数不会被执行。
示例函数需要归属于某个 包/函数/类型/类型 的方法,具体命名规则如下:
1
2
3
4
5
6
7
8
9
10
|
func Example() { ... } # 包的示例函数 func ExampleF() { ... } # 函数F的示例函数 func ExampleT() { ... } # 类型T的示例函数 func ExampleT_M() { ... } # 类型T的M方法的示例函数 # 多示例函数 需要跟下划线加小写字母开头的后缀 func Example_suffix() { ... } func ExampleF_suffix() { ... } func ExampleT_suffix() { ... } func ExampleT_M_suffix() { ... } |
go doc 工具会解析示例函数的函数体作为对应 包/函数/类型/类型的方法 的用法。
测试函数的相关说明,可以通过go help testfunc来查看帮助文档。
使用 go test 工具
Golang中通过命令行工具go test来执行测试代码,打开shell终端,进入需要测试的包所在的目录执行 go test,或者直接执行go test $pkg_name_in_gopath
即可对指定的包执行测试。
通过形如go test github.com/tabalt/...
的命令可以执行$GOPATH/github.com/tabalt/
目录下所有的项目的测试。go test std
命令则可以执行Golang标准库的所有测试。
如果想查看执行了哪些测试函数及函数的执行结果,可以使用-v参数:
1
2
3
4
5
6
7
|
[tabalt@localhost hello] go test -v === RUN TestHello --- PASS: TestHello (0.00s) === RUN ExampleHello --- PASS: ExampleHello (0.00s) PASS ok hello 0.006s |
假设我们有很多功能测试函数,但某次测试只想执行其中的某一些,可以通过-run参数,使用正则表达式来匹配要执行的功能测试函数名。如下面指定参数后,功能测试函数TestHello不会执行到。
1
2
3
|
[tabalt@localhost hello] go test -v -run=xxx PASS ok hello 0.006s |
性能测试函数默认并不会执行,需要添加-bench参数,并指定匹配性能测试函数名的正则表达式;例如,想要执行某个包中所有的性能测试函数可以添加参数-bench . 或 -bench=.。
1
2
3
4
|
[tabalt@localhost hello] go test -bench=. PASS BenchmarkHello-8 2000000 657 ns/op ok hello 1.993s |
想要查看性能测试时的内存情况,可以再添加参数-benchmem:
1
2
3
4
|
[tabalt@localhost hello] go test -bench=. -benchmem PASS BenchmarkHello-8 2000000 666 ns/op 208 B/op 9 allocs/op ok hello 2.014s |
参数-cover可以用来查看我们编写的测试对代码的覆盖率:
1
|
|
详细的覆盖率信息,可以通过-coverprofile输出到文件,并使用go tool cover来查看,用法请参考go tool cover -help
。
更多go test
命令的参数及用法,可以通过go help testflag
来查看帮助文档。
高级测试技术
IO相关测试
testing/iotest包中实现了常用的出错的Reader和Writer,可供我们在io相关的测试中使用。主要有:
触发数据错误dataErrReader,通过DataErrReader()
函数创建
读取一半内容的halfReader,通过HalfReader()
函数创建
读取一个byte的oneByteReader,通过OneByteReader()
函数创建
触发超时错误的timeoutReader,通过TimeoutReader()
函数创建
写入指定位数内容后停止的truncateWriter,通过TruncateWriter()
函数创建
读取时记录日志的readLogger,通过NewReadLogger()
函数创建
写入时记录日志的writeLogger,通过NewWriteLogger()
函数创建
黑盒测试
testing/quick包实现了帮助黑盒测试的实用函数 Check和CheckEqual。
Check函数的第1个参数是要测试的只返回bool值的黑盒函数f,Check会为f的每个参数设置任意值并多次调用,如果f返回false,Check函数会返回错误值 *CheckError。Check函数的第2个参数 可以指定一个quick.Config类型的config,传nil则会默认使用quick.defaultConfig。quick.Config结构体包含了测试运行的选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# /usr/local/go/src/math/big/int_test.go func checkMul(a, b []byte) bool {
var x, y, z1 Int
x.SetBytes(a)
y.SetBytes(b)
z1.Mul(&x, &y)
var z2 Int
z2.SetBytes(mulBytes(a, b))
return z1.Cmp(&z2) == 0
} func TestMul(t *testing.T) { if err := quick.Check(checkMul, nil); err != nil {
t.Error(err)
}
} |
CheckEqual函数是比较给定的两个黑盒函数是否相等,函数原型如下:
1
|
func CheckEqual(f, g interface{}, config *Config) (err error) |
HTTP测试
net/http/httptest包提供了HTTP相关代码的工具,我们的测试代码中可以创建一个临时的httptest.Server来测试发送HTTP请求的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client" )
})) defer ts.Close() res, err := http.Get(ts.URL) if err != nil {
log .Fatal(err)
} greeting, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil {
log .Fatal(err)
} fmt.Printf( "%s" , greeting)
|
还可以创建一个应答的记录器httptest.ResponseRecorder
来检测应答的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
handler := func(w http.ResponseWriter, r *http.Request) { http.Error(w, "something failed" , http.StatusInternalServerError)
} if err != nil {
log .Fatal(err)
} w := httptest.NewRecorder() handler(w, req) fmt.Printf( "%d - %s" , w.Code, w.Body.String())
|
测试进程操作行为
当我们被测函数有操作进程的行为,可以将被测程序作为一个子进程执行测试。下面是一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//被测试的进程退出函数 func Crasher() { fmt.Println( "Going down in flames!" )
os.Exit(1)
} //测试进程退出函数的测试函数 func TestCrasher(t *testing.T) { if os.Getenv( "BE_CRASHER" ) == "1" {
Crasher()
return
}
cmd := exec.Command(os.Args[0], "-test.run=TestCrasher" )
cmd.Env = append(os.Environ(), "BE_CRASHER=1" )
err := cmd.Run()
if e, ok := err.(*exec.ExitError); ok && !e.Success() {
return
}
t.Fatalf( "process ran with err %v, want exit status 1" , err)
} |
go test 用args带参数
1.报错的写法:
go test -v -run="Test_main" -args "-c 1"
go test -v -run="Test_main" -args "-c=1"
go test -v -run="Test_main" -args -c=1
总之,args后面的自定义参数不能带减号-
2.正确的写法,上面“-c”去掉减号。
3.但是代码里面不能用如下传统方法:
flag.IntVar(&cmd, "c", 0, cmdhelp)
flag.Parse()
4.目前我的做法:
for _, arg := range flag.Args() {
arglist := strings.Split(arg, "=")
if len(arglist) != 2 {
arglist = strings.Split(arg, " ")
}
if len(arglist) != 2 {
fmt.Printf(" unknown arg:%v\n", arg)
continue
}
arg0 := strings.TrimSpace(arglist[0])
if arg0 == "c" || arg0 == "C" {
cmd = stringToInt1(strings.TrimSpace(arglist[1]))
}
}
if cmd == 0 {
fmt.Printf(`
Usage:
go test -v -run="Test_main" -args "c 1"
or
go test -v -run="Test_main" -args c=1
`)
return
}
依据:
go test -v -run="Test_main" -args "c 1" a=1 d=3 f="3e"
=== RUN Test_main
os.Args:[**test.exe -test.v=true -test.run=Test_main c 1 a=1 d=3 f=3e]
flag.Args():[c 1 a=1 d=3 f=3e]
Golang测试包
golang自带了测试包(testing),直接可以进行单元测试、性能分析、输出结果验证等。简单看着官方文档试了试,总结一下:
目录结构和命令
使用golang的测试包,需要遵循简单的目录结构
测试代码放在待测试代码的目录下(一个包内),以_test.go结尾,例如如下目录结构,MyTest目录下有待测试的代码文件MyTest.go和测试代码MyTest_test.go
.
|-- bin
| `-- main
|-- pkg
| `-- darwin_amd64
| `-- MyTest.a
`-- src
|-- MyTest
| |-- MyTest.go
| `-- MyTest_test.go
`-- main
`-- main.go
直接在MyTest目录下执行go test命令即可,go test包含很多选项,可以参考Golang手册相关部分
基本的测试函数
待测试的MyTest.go源码如下:
package MyTest
import (
"fmt"
)
type MyStruct struct {
name string
}
func GetFieldValue(x *MyStruct) string {
value := x.name
return value
}
func SetFieldValue(x *MyStruct, value string) {
fmt.Println("SetFieldValue()")
x.name = value
}
对于MyTest_test.go,首先自然是要导入golang的测试包:
package MyTest
import testing
基本的测试函数以Test开头,后面接的字符串,第一个字符必须是数字或者大写,例如:
func TestMytest(t *testing.T) {
var st MyStruct
SetFieldValue(&st, "hello")
val := GetFieldValue(&st)
if val != "hello" {
t.Error("Set Field")
}
}
T是testing包里定义的一个结构体,其包含了名为common的接口,提供了很多格式化输出的功能,golang提供了自动检查与调用测试函数的机制,测试函数的执行逻辑则需要编写者自行完成。
执行go test 结果为:
Call SetFieldValue()
PASS
ok /go/src/MyTest 0.004s
如果写成Testmytest,运行时会直接忽略掉该函数。得到的结果仍然为Pass,但是不会打印“Call SetFieldValue()”,也就是说测试函数实际没有执行。
修改一下判断条件:
func TestMytest(t *testing.T) {
var st MyStruct
SetFieldValue(&st, "hello")
val := GetFieldValue(&st)
if val != "world" {
t.Error("Set Field")
}
}
这个测试用例不会通过, 而Error函数的入参就是测试不通过时打印的信息:
SetFieldValue()
--- FAIL: TestMytest (0.00s)
MyTest_test.go:15: Set Field
FAIL
exit status 1
FAIL _/Users/ronghuihe/Documents/code/golang/my/go/src/MyTest 0.004s
这并不会中断测试程序,这个函数后面的部分仍然会执行,其他的测试函数也会执行。
性能分析函数
testing包还自带了性能分析功能,可评估代码执行性能。性能分析函数也可以放到前面的xxx_test.go文件内,命名以Benchmark开头,如:
func BenchmarkGetFieldValue(b *testing.B) {
var st MyStruct
SetFieldValue(&st, "hello")
for i := 0; i < b.N; i++ {
GetFieldValue(&st)
}
}
其中b.N的值在执行过程中会自动调整,使得循环可以执行足够多次,以便得到较为准确的单次结果:
性能分析加-bench参数执行,即go test -bench . (不能漏了最后这个点,它表示执行所有的性能测试函数)
BenchmarkGetFieldValue SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
2000000000 0.55 ns/op
每次循环大约需要0.55ns。这里SetFieldValue()打印了多次,是因为BenchmarkGetFieldValue被调用了多次。
分析testing包的源码benchmark.go里的launch函数和runN函数,可以看到golang会自行调节性能分析函数的调用次数。每次执行runN都会执行一次性能测试函数,而后根据运行时间,会确定后续的内部循环执行次数b.N,直到总的运行时间达到go test -benchtime指定的时间(如果没指定默认为1s)
注意统计时间时,执行的是使用者编写的性能分析函数,如上例中的BenchmarkGetFieldValue,而最后输出的结果,表达的是for循环里函数的性能,因此for循环之前的代码执行时间很长的话,可能导致统计误差比较大,如果需要剔除for之前代码的影响,可以在for循环之前调用ResetTimer()接口重置本次统计的时间值:
func BenchmarkGetFieldValue(b *testing.B) {
var st MyStruct
SetFieldValue(&st, "hello")
b.ResetTimer()
for i := 0; i < b.N; i++ {
GetFieldValue(&st)
}
}
Go测试,功能测试,性能测试,测试辅助,go test 工具,高级测试,IO相关测试,黑盒测试,HTTP测试,进程测试的更多相关文章
-
H5测试点总结-UI测试、功能测试、兼容性测试、体验相关(弱网、资源、手机操作等)、安全性测试、性能测试
一.概述 1.1 什么是H5 H5 即 HTML5,是最新的 Web 端开发语言版本,现如今,大多数手机 APP 页面会用 H5 实现,包括 PC Web 站点也会用它开发实现.所以 Web 的通用测 ...
-
[转贴]LTP--linux稳定性测试 linux性能测试 ltp压力测试 ---IBM 的 linux test project
https://blog.csdn.net/melody157398/article/details/24354415 LTP--linux稳定性测试 linux性能测试 ltp压力测试 ---I ...
-
LTP--linux稳定性测试 linux性能测试 ltp压力测试 ---IBM 的 linux test project
LTP--linux稳定性测试 linux性能测试 ltp压力测试 ---IBM 的 linux test project Peter盼 2014-04-23 11:25:49 20302 收藏 ...
-
APP测试--功能测试
1.1 了解需求 这一点,不但是功能测试,是所有测试都需要的第1步.通过需求文档,与产品经理的沟通,与开发的沟通,用户的使用习惯等各方法,了解APP的需求. 1.2 编写测试用例 当然之前可能是测试计 ...
-
【测试】性能测试及性能测试工具Loadrunner
性能测试简介 软件系统的性能包括很多方面,有执行效率,资源占用,系统稳定性,安全性,兼容性,可靠性,可扩展性等.这些都是可以衡量一个软件系统性能好坏的指标.而性能测试是指通过自动化测试工具去模拟多种正 ...
-
LTP--linux稳定性测试 linux性能测试 ltp压力测试 内核更新 稳定性测试
LTP--linux稳定性测试 linux性能测试 ltp压力测试 zhangzj1030关注14人评论33721人阅读2011-12-09 12:07:45 说明:在写这篇文章之前,本人也不曾了 ...
-
LTP--linux稳定性测试 linux性能测试 ltp压力测试 ltp-pan
LTP--linux稳定性测试 linux性能测试 ltp压力测试 zhangzj1030关注14人评论33710人阅读2011-12-09 12:07:45 说明:在写这篇文章之前,本人也不曾了 ...
-
功能测试很low?不能升级到高级测试工程师?
功能测试很low?不能升级到高级测试工程师? 功能测试很low?功能测试很简单?功能测试就是黑盒测试?功能测试没有技术含量?功能测试工资低?只会功能测试没有竞争力?功能测试这活初中生都可以干?功能测试 ...
-
flask模板的基本用法(定界符、模板语法、渲染模板),模板辅助工具(上下文、全局对象、过滤器、测试器、模板环境对象)
flask模板 在动态web程序中,视图函数返回的HTML数据往往需要根据相应的变量(比如查询参数)动态生成. 当HTML代码保存到单独的文件中时,我们没法再使用字符串格式化或拼接字符串的当时在HTM ...
随机推荐
-
x01.TodoList:Asp.Net 5 初探
ASP.NET 5 是比较新的,除了汤姆的博文,学习资料并不多.而学习没有例子上手,是比较痛苦的. 1.运行 vs2015,新建项目,选择 Asp.Net 5 WebApp 模板,默认运行即可.对照汤 ...
-
Bete冲刺第一阶段
Bete冲刺第一阶段 今日工作: github团队协作流程 web:调整dao层设计,增加新的dao组件 客户端:之前遗留的界面跳转的BUG 目前所遇问题: 第一,COCOAPODS的安装上还是有点问 ...
-
关于Block Formatting Context--BFC和IE的hasLayout
转文请标明 --- 出处:穆乙 http://www.cnblogs.com/pigtail/ 一.BFC是什么? BFC(Block Formatting Context)直译为"块级格式 ...
-
PHP 上传文件和读取文件崎岖路
今天php上传文件和读取文件没有搞出来,全靠后来大神来帮忙,总结一下:主要涉及到一下几个方面,在ubuntu下mkdir文件夹的时候要注意权限问题,一般情况下php是以一个较低的权限去执行的,所以如果 ...
-
linux 修改端口限制
1.显示当前临时端口的范围:一般情形下:linux临时端口号范围是(32768,61000) sysctl net.ipv4.ip_local_port_range 或 cat ...
-
SQL拾遗
前两天同事问了个SQL问题,有个出价记录表[针对不同拍品出价],每个人都可以多次出价,要查下哪些拍品出价最高的人和出价次高的人是同一个人的记录,当时写了下面的SQL,今天先记下了,欢迎补充新的查询方式 ...
-
Go学习笔记(二)十分钟上手
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 变量&常量 变量 变量名由字母.数字.下划线组成,不能以数字开头. ... var ( A int //默 ...
-
Es6 类的关键 super、static、constructor、new.target
ES6引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类.基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对 ...
-
201521123070 《JAVA程序设计》第6周学习总结
1. 本章学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
-
Oracle获取表字段名,字段类型,字段长度,注释
SELECT b.comments as 注释, a.column_name as 列名, a.data_type || '(' || a.data_length || ')' as 数据类型, a. ...