Как мне изменить мой код, чтобы он был совместим с этим тестом? - PullRequest
0 голосов
/ 23 января 2020

Я работаю над упражнением на веб-сайте Exercism, и я написал программу, но она не проходит ни одного из тестов, через которые Exercism ее проводит. Я не совсем знаю, что мне нужно сделать, чтобы это исправить, хотя. Вот мой код:

import random

ABILITIES = ['strength', 'dexterity', 'constitution',
             'intelligence', 'wisdom', 'charisma']

class Character:
    def __init__(self):
        for ability in ABILITIES:
            setattr(self, ability, roll_ability())
        self.hitpoints = 10 + modifier(self.constitution)


def modifier(constitution):
    return (constitution - 10) // 2


def roll_ability(dice=4, sides=6):
    rolls = []
    for die in range(dice):
        rolls.append(random.randint(1, sides))
    rolls.remove(min(rolls))
    return sum(rolls)

Вот код из тестового файла, который он терпит неудачу:

def test_random_ability_is_within_range(self):
        score = Character().ability()
        self.assertIs(score >= 3 and score <= 18, True)

А вот сообщение об ошибке:

________________________________ DndCharacterTest.test_random_ability_is_within_range _________________________________

self = <dnd_character_test.DndCharacterTest testMethod=test_random_ability_is_within_range>

    def test_random_ability_is_within_range(self):
>       score = Character().ability()
E       AttributeError: 'Character' object has no attribute 'ability'

dnd_character_test.py:58: AttributeError

I думаю, мне нужен атрибут объекта с именем "способность?" Но что это делает? Я не фанат того, что нужно писать программу именно так, чтобы она могла пройти юнит-тест! Я думаю, мне нужно прочитать unittest, прежде чем я начну писать код, чтобы я мог знать, что делать?

Спасибо!

1 Ответ

1 голос
/ 23 января 2020

Прочитав описание упражнения D & D Character , это просто не указано . Вы вправе испытывать неловкость из-за необходимости полагаться на тесты, чтобы предоставить вам спецификации, это должно было быть более четко описано в вашем задании.

В ходе теста, безусловно, ожидается, что Character().ability() метод, и он проверяет, что этот метод возвращает целое число в диапазоне 3-18 включительно. Итак, читая между строк того, что в описании рассказывается о том, как рассчитываются способности и что ищет тест, вам просто нужно переместить вашу функцию roll_ability() в ваш класс Character и переименовать ее ability():

class Character:
    def __init__(self):
        for ability in ABILITIES:
            setattr(self, ability, self.ability())
        self.hitpoints = 10 + modifier(self.constitution)

    def ability(self, dice=4, sides=6):
        rolls = []
        for die in range(dice):
            rolls.append(random.randint(1, sides))
        rolls.remove(min(rolls))
        return sum(rolls)

Ваша собственная реализация уже производит числа от 3 до 18 включительно (сумма 3 самых высоких костей выкатывается из 4), поэтому должен пройти тест без проблем. Я подтвердил, что вышеприведенная реализация (плюс ваша modifier() функция) действительно проходит указанные модульные тесты.

С точки зрения дизайна вы были правы в использовании здесь отдельной функции. ability() не зависит от какого-либо состояния Character и не является функцией, которую должен выполнять экземпляр символа. Вместо того, чтобы делать это методом (с бесполезным аргументом self), вы можете пойти на компромисс и сделать его @staticmethod:

class Character:
    def __init__(self):
        for ability in ABILITIES:
            setattr(self, ability, self.ability())
        self.hitpoints = 10 + modifier(self.constitution)

    @staticmethod
    def ability(dice=4, sides=6):
        rolls = []
        for die in range(dice):
            rolls.append(random.randint(1, sides))
        rolls.remove(min(rolls))
        return sum(rolls)

Что касается функции ability() реализации, вы можете захотеть взглянуть на функцию heapq.nlargest() , чтобы аккуратно и эффективно выбрать 3 верхних из 4 бросков кубиков здесь:

from heapq import nlargest

class Character:
    # ...

    @staticmethod
    def ability(dice=4, sides=6):
        rolls = (random.randint(1, sides) for _ in range(dice))
        return sum(nlargest(dice - 1, rolls))

Я бы просто бросил аргументы dice и sides здесь на основе YAGNI или не менее перемещают маги c числа 4 и 6 в глобальный верхний регистр имена вверху.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...