您的问题源于您正在使用现场注射,而不是使用基于构造函数的注入的最佳实践。除了您已经注意到的前者生产的代码很难测试的事实外,它还具有其他缺点。例如:
- 它不允许创建不变的组件(IE字段不是
final
), - 它可能导致代码违反了单个责任原则(因为您很容易地注入了大量可能没有关注的依赖项
- )夫妻直接与DI容器直接使用代码(即,您不能轻松地在DI容器之外使用代码),
- 它可能会隐藏注射的依赖关系(即可选和必需之间没有明确的区分依赖项)。
基于所有这些,如果您使用构造函数注入来完成工作,那会更好。因此,将模拟注入服务的位置可以很容易地完成:
@Mock // The mock we need to inject
private MyMockedService mockedService;
@InjectMocks // The unit we need to test and inject mocks to
private MyUnitToTestServiceImpl unitToTestService;
或者,您可以使用实例化直接测试的设备,然后简单地通过其公共构造函数传递在模拟实例中。
因此,经验法则是在这种情况下始终使用构造函数注入。
- 说我们考虑
swapexacttokensfortokens
uniswapv2Router
的方法返回uint []内存量
。
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
- 引用在这里 >
这是我能够解决这个问题的方式:
- 在固体合同中,就在返回之前,我生成了一个包含即将返回的值的事件。
- 在Python代码中,我提取返回的值:
[...]
data = router.swapExactTokensForTokens(
tokens[1].balanceOf(account),
1,
path,
attacker,
chain.time(),
{"from": account},
)
>>> int(web3.eth.getTransactionReceipt(data.txid)["logs"][2]["data"], 16)
631376138468681379
-
这将为我们提供
MANES0OUT
的值。 -
您可以看到
events
像这样
>>> data.events
{'Approval': [OrderedDict([('owner', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('spender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('value', 4500000000000000000)])], 'Transfer': [OrderedDict([('from', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('to', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('value', 500000000000000000)]), OrderedDict([('from', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('value', 631376138468681379)])], 'Sync': [OrderedDict([('reserve0', 14368623861531318621), ('reserve1', 11844678011344678012)])], 'Swap': [OrderedDict([('sender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('amount0In', 0), ('amount1In', 500000000000000000), ('amount0Out', 631376138468681379), ('amount1Out', 0), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3')])]}
- 我正在使用
eth-brownie
。
如果我理解问题是正确的,我会这样继续(Inline评论尝试解释逻辑),
// first we start the stream with the initial list of items (an array notified
// by the initialObservable)
initialObservable.pipe(
// once initialObservable notifies the list we switch to another observable
switchMap(items => {
// the stream we switch to starts with the stream of mutations
return mutationObservable.pipe(
// we need to notify something since the very beginning, not only from
// when the first mutation occurs, therefore we use startWith to say
// that the new stream starts immediately notifying a null (assuming
// there is no null key in items)
startWith(null),
// since we need to keep a state but also to notify the state any time
// an event from upstream (i.e. a mutation) occurs, then we use the
// scan operator which holds an internal state which is notified any time
// upstream notifies something
scan((state, m) => {
// the state, i.e. the list of items, gets updated according to the
// mutations received from upstream
state = state.filter(item => item.id !== m)
// scan returns a new state
return state
}, items) // the state is initialized with the items received
)
})
)
您可以看一下此stackblitz 示例。
问题似乎是 testscope.runtest
将等待所有儿童coroutines在提供测试结果之前完成。
执行不会陷入延迟(30_000)
中。导致测试永远运行的原因是,您的断言失败并抛出了 essertionError
。由于抛出了错误,因此从未调用下一行 viewModel.onstop()
。这意味着您在ViewModel中启动的Coroutine永远不会完成,因此 testscope.runtest
永远不会提供结果。
您可以轻松测试:
...
println("after delay; before assertion")
try{
assertEquals(6, viewModel.count)
}catch (e: AssertionError){
e.printStackTrace()
throw e
}
println("after assertion")
viewModel.onStop()
最简单的解决方案是首先调用 viewmodel.onstop()
,然后运行您想要的任何断言。
如果您关心一种完全替代方法,则可以避免完全手动开始和停止视图模式,然后选择更“ coroutine-y”的方法:
class AndroidTestViewModel(
val injectedDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ViewModel() {
var count = 0
suspend fun doWhileInForeground(){
withContext(injectedDispatcher){
while (true) {
delay(5000)
count++
}
}
}
}
测试这可能会更像是这样:
@Test
fun interval() = scope.runTest {
val viewModel = AndroidTestViewModel(injectedDispatcher)
launch {
viewModel.doWhileInForeground()
}
delay(30_000)
assertEquals(6,viewModel.count)
}
并且在片段中使用了一个示例,这很容易适应活动或JetPack组成:
class SampleFragment: Fragment(){
val viewModel: AndroidTestViewModel = TODO()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.doWhileInForeground()
}
}
}
}
您无法确定传递的数组内部功能的大小。您需要将大小作为附加参数传递。
const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0};
void count_chars(const char *arr, unsigned int *counts, size_t size)
{
for(size_t i = 0; i < size; i++)
counts[(unsigned)arr[i]]++;
}
int main(void)
{
int cnt[sizeof(array[0]) * (1 << CHAR_BIT)];
count_chars(array, cnt, sizeof(array) / sizeof(array[0]));
}
您需要施放到无符号
(不是 int
),因为 char> char
值可能为负。
由于MongoDB版本4.4*,一个选项是将聚合管道与 $降低
, $ mod
, $ filter
和 $ zip
:
-
$ ydre
带有$ mod
添加一个新mod
字段到每个项目,带有Value0
每个奇数索引(1, 3,5,...)和值1
偶数索引(2,4,6,... - ) > mod value
- <代码> $ zip 这两个阵列到一对夫妻的数组,
db.collection.aggregate([
{
$project: {
events: {
$reduce: {
input: "$events",
initialValue: [],
in: {$concatArrays: [
"$value",
[
{
timestamp: "$this.timestamp",
status: "$this.status",
mod: {$mod: [{$size: "$value"}, 2]}
}
]
]
}
}
}
}
},
{
$project: {
firstEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 0]}}},
secondEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 1]}}}
}
},
{$project: {couples: {$zip: {inputs: ["$firstEvent", "$secondEvent"]}}}}
])
看看它在 playground示例示例
*与较旧的mongodb版本,3.4或更高版本, $ mod
可以是替换为“手动” mod
计算。
这里的主要目标是编写类型函数类型schematotype&lt; t&gt; = ...
将架构类型作为输入,并产生相应的值类型作为输出。因此,您想要 schematotype&lt; {type:“ string”}&gt;
be string
,以及 schematotype&lt; {type:“ array”,tyme:type:type:type:type: “ number”}}}&gt;
be number []
等。
首先,我们可能应该写一个 schema
键入该键模式类型可分配给。这不是严格必要的,如果愿意,您可以做不同的事情,但是这是一种方法:
type Schema = ObjectSchema | ArraySchema | PrimitiveSchema | OneOf | AnyOf;
type ObjectSchema = {
type: "object",
properties: Record<string, Schema>,
}
type ArraySchema = {
type: "array",
items: Schema,
}
interface PrimMapping {
string: string,
integer: number,
number: number,
// add here
}
type PrimitiveSchema = {
type: keyof PrimMapping,
}
interface OneOf {
oneOf: readonly Schema[]
}
interface AnyOf {
anyOf: readonly Schema[]
}
当然,您可以使用其他模式类型来增强此定义。您可以看到架构
是联合特定架构类型的类型,其中一些( Objectschema
, arrayschema
,单一
和 anyof
)是按 schema
本身递归定义的。
我为什么要允许 /code>数组是因为它比常规读取阵列的限制类型较小,并且因为 /a>倾向于导致可读的元组类型。
因此,这是编写 schematotype&lt; t&gt;
的一种方法:
type SchemaToType<T extends Schema> =
Schema extends T ? unknown :
T extends OneOf ? SchemaToType<T['oneOf'][number]> :
T extends AnyOf ? SchemaToType<T['anyOf'][number]> :
T extends PrimitiveSchema ? PrimMapping[T['type']] :
T extends ObjectSchema ? {
- readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
} :
T extends ArraySchema ? SchemaToType<T['items']>[] :
never;
这是递归条件类型。这个想法是,我们浏览每个 schema
联合成员并将其转换为相应的值类型。好吧,我们要做的第一件事是架构扩展t?未知:
,这意味着如果 t
正是 schema
本身,我们将缩短计算并返回 the 未知
类型。这种事情对于避免循环警告是必要的,因为否则 schematotype&lt; schema&gt;
最终将永远递归自己。
让我们看一下该类型的其他行:
T extends OneOf ? SchemaToType<T['oneOf'][number]> :
如果 t
是 Oneof
,那么我们需要 index Oneof
属性,该属性将是模式的数组...因此,我们将其进一步索引 number
valued属性(提供数组元素类型)。 t ['Oneof'] [number]
将是数组中模式类型的结合。而且由于 schematotype
是(主要是)a 分配条件类型,然后 schematotype&lt; t ['Oneof'] [number]&gt;
本身将是该联合每个元素的价值类型的结合。所有这些都意味着输出类型将是所有 Oneof
数组元素值类型的联合。
T extends AnyOf ? SchemaToType<T['anyOf'][number]> :
如果 t
是 anyof
,我们与 Oneof
做同样的事情。大概您的架构在乎“任何”和“一个”和“一个”之间的区别,但是在打字稿中,这两者都以联盟为代表。如果您真的很关心差异,则可以使用 Oneof 构建一个“独家”联盟, 2887218“>这个问题,但我认为这是出于范围。
T extends PrimitiveSchema ? PrimMapping[T['type']] :
这是简单的...我写了 primmapping
是来自 type
名称到原始类型的地图。因此,如果 t
是 {type:“ integer”}
,则值类型为 primmapping [“ integer”]
,它被证明为号码
。
T extends ObjectSchema ? {
- readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
} :
如果 t
是 objectschema
,那么我们将映射类型从 properties
属性上的每个键上的类型 t
。最后:
T extends ArraySchema ? SchemaToType<T['items']>[] :
如果 t
是 arrayschema
,那么我们将与 items
属性的类型进行数组>。
让我们测试一下:
const spec = {
type: 'object',
properties: {
str: {
type: 'string',
},
strOrNum: {
oneOf: [{ type: 'string' }, { type: 'number' }],
example: 30
},
strArr: {
type: 'array',
items: {
type: 'string'
}
}
}
} as const;
type SpecType = SchemaToType<typeof spec>
/* type SpecType = {
str: string;
strOrNum: string | number;
strArr: string[];
} */
看起来不错!
当您实现某些函数或类方法,该函数或类方法是类型 schema
并产生示例时,您可能会遇到一些问题,使编译器可以推断出架构的正确类型。如果将上述 spec
initializer不用作为const ,则编译器甚至不会记住特定的字面类型 类型
属性和事物中断:
const specOops = {
type: 'object',
properties: {
str: {
type: 'string',
},
strOrNum: {
oneOf: [{ type: 'string' }, { type: 'number' }],
example: 30
},
strArr: {
type: 'array',
items: {
type: 'string'
}
}
}
} ;
type SpecTypeOops = SchemaToType<typeof specOops> // error!
因此,如果将事物保存到他们自己的变量中,则需要或类似的东西。
您可以以使编译器尝试从其输入中推断出狭窄类型的方式编写功能/方法,但这有点令人讨厌。请参阅 Microsoft/typeScript#30680 对于功能请求,可以更轻松地使其更容易。这是实现它的一种方法:
type SchemaHelper<T, K extends Types> = Schema & (
{ oneOf: readonly [] | readonly SchemaHelper<T, K>[] } |
{ anyOf: readonly [] | readonly SchemaHelper<T, K>[] } |
{
type: K,
properties?: Record<string, SchemaHelper<T, K>>,
items?: SchemaHelper<T, K>
}
);
declare function schemaToExample<
T extends SchemaHelper<T, K>, K extends Types
>(schema: T): SchemaToType<T>;
所有 schemahelper
确实是要求编译器注意 type
字面类型和单个数组类型和值。但是Yuck。
无论如何,让我们测试一下:
const ex2 = schemaToExample({
type: 'object',
properties: {
firstName: {
type: 'string',
example: 'Johnbob',
},
lastName: {
type: 'string',
// No example provided
},
age: {
type: 'integer',
example: 30
},
}
});
/* const ex2: {
firstName: string;
lastName: string;
age: number;
} */
const ex2a = schemaToExample({
oneOf: [{
type: 'object',
properties: {
name: {
type: 'string',
example: 'Beer'
},
liters: {
type: 'integer',
example: 1
}
}
},
{
type: 'object',
properties: {
name: {
type: 'string',
example: 'Movie'
},
lengthInMins: {
type: 'integer',
example: 120
}
}
}
]
}
);
/* const ex2a: {
name: string;
liters: number;
} | {
name: string;
lengthInMins: number;
} */
const ex3 = schemaToExample({
type: 'object',
properties: {
firstName: {
type: 'string',
example: 'Johnbob',
},
lastName: {
type: 'string',
// No example provided
},
age: {
type: 'integer',
example: 30
},
favoriteThing: {
oneOf: [{
type: 'object',
properties: {
name: {
type: 'string',
example: 'Beer'
},
liters: {
type: 'integer',
example: 1
}
}
},
{
type: 'object',
properties: {
name: {
type: 'string',
example: 'Movie'
},
lengthInMins: {
type: 'integer',
example: 120
}
}
}
]
}
}
});
/* const ex3: {
firstName: string;
lastName: string;
age: number;
favoriteThing: {
name: string;
liters: number;
} | {
name: string;
lengthInMins: number;
};
} */
我认为看起来不错。输出类型是您想要的。
您可以使用Broom的增强
(用于PC)和整理
(用于加载)在 ggplot
ing之前获取数据框:
library(tidyverse)
library(broom)
data <- tribble(
~Profession, ~il.count.ratio, ~elle.count.ratio, ~un.count.ratio, ~une.count.ratio,
"secretary", 1.7241, 1.3514, 1.473, 0.7380,
"secretary", 0.0000, 2.8736, 2.8536, 0.8370,
"driver", 1.7065, 0.0000, 0.0000, 0.7380,
"driver", 0.5284, 1.4733, 0.7380, 0.5280
)
data %>%
select(il.count.ratio:une.count.ratio) %>%
prcomp() %>%
augment(data) %>%
ggplot(aes(.fittedPC1, .fittedPC2, colour = Profession)) +
geom_point()
# Use instead of augment for the loadings
# tidy(matrix = "loadings")
在2022-06-30创建的 reprex软件包(v2.0.1)
在Moodle中,您可以使用主题插件渲染器来渲染核心输出。
请参阅主题渲染器方法。
您可以使用当前运行的主题覆盖Full_header HTML内容。
以下步骤将帮助您更改完整的标题。
-
在当前运行主题“模板”文件夹中创建文件夹“ core”。
IE 主题\ boost \ templates \ core -
从lib \ templates文件夹中复制 full_header.mustache 到新创建的主题\ temot \ template \ core foldlate \ core文件夹。
-
进行主题\ templates \ full_header.mustache 文件
的更改
- 进行 themplates \ full_header.mustache 文件
清除 site admin&gt中的缓存
;开发&GT;吹扫库
df$Delta1 <- ifelse(!is.na(df$Time1) & !is.na(df$Time2) & !is.na(df$Time3),
df$Time2 - df$Time1,
NA)
df$Delta2 <- vapply(seq_len(nrow(df)), \(x){
x = na.omit(c(df$Time3[x], df$Time2[x], df$Time1[x]))
x = x[1] - x[2]
if(is.na(x)) return(0)
return(x)
}, 0)
结果:
> df
ID Type Time1 Time2 Time3 Delta1 Delta2
1 1 A1 12.23 NA NA NA 0.00
2 2 A1 0.35 0.53 NA NA 0.18
3 2 A2 5.78 NA 10.25 NA 4.47
4 3 A5 NA NA 4.19 NA 0.00
5 4 A3 NA 3.18 7.15 NA 3.97
6 5 A5 10.91 4.56 2.45 -6.35 -2.11
在 tick()
函数中,请勿调用 turtle.ontimer(tick,frame_delay_ms)
在游戏结束时。您可以将该调用移至功能末尾,并设置一个确定是否应调用其的标志。
def tick():
snake.move()
screen.update()
# Flag
game_over = False
# Detect Collision With Food
if snake.head.distance(food) < 20:
food.reset_food_location()
snake.extend()
scoreboard.increase_score()
# Detect Collision With Wall
if snake.head.xcor() == 300 or snake.head.xcor() == -300 \
or snake.head.ycor() == 300 or snake.head.ycor() == -300:
scoreboard.game_over()
game_over = True # Set flag
# Detect Collision With Tail
for segment in snake.segments[1:]:
if snake.head.distance(segment) < 10:
scoreboard.game_over()
game_over = True # Set flag
break
# Only call if game is NOT over
if not game_over:
turtle.ontimer(tick, frame_delay_ms)
您可以在打印出来之前使用Streams API进行排序:
Comparator<Entry<String, Map<String, Integer>>> entryComparator =
Comparator.comparingInt((Entry<String, Map<String, Integer>> entryOne) -> entryOne.getValue().size());
for(Entry<String, Map<String, Integer>> entry : states.entrySet().stream().sorted(entryComparator.reversed()).collect(
Collectors.toList())) {
System.out.println("State:" + entry.getKey());
Map<String, Integer> tempMap = entry.getValue();
for(Entry<String, Integer> innerEntry : tempMap.entrySet()) {
System.out.println("City:" + innerEntry.getKey() + " Count:" + innerEntry.getValue());
}
System.out.println();
}
搜索网络我找不到答案或提示来解释错误消息。
转到另一个教程后,我了解了我的错误。
这是一个简单的“案例敏感”语法错误命名Docker文件的命名。
我将其命名为“ Dockerfile”,它应该被命名为“ Dockerfile”。
这是项目中所有其他文件名中的独特命名约定,它们都是小写或所有大写。
一条更好的错误消息将是“错误:丢失Dockerfile”,这足以让我找到原因。
设置器和Getter必须使用相同的类型。
就您而言,要么是字符串或枚举。
一个人无法混合这些:
考虑以下,功能性的代码,该代码也将两种类型都用于同一变量。
当人们定义具有不匹配类型的getter和setter时,这就是它看起来像飞镖的一样:
Setter and Getter must use the same Type.
In your case, either a String or an Enum.
One cannot mix these:
Consider the following, disfunctional code, which also uses both types for the same variable.
This is how it looks to Dart when one defines a Getter and Setter with not-matching Types:
回报枚举时的回报类型的奇怪行为